WEB通用漏洞-反序列化
WEB通用漏洞-反序列化
前置知识
序列化/反序列化
序列化:对象/数组转换为字符串的格式(二进制数据流)。
反序列化:将字符串格式转换成对象/数组。
对象/数组序列化的作用:保存当前对象/数组的状态(确保状态不丢失),便于进行对象/数组的存储和传输(提高对象/数组的持久性)。
以php为例,序列化函数和反序列化函数
serialize() // 序列化
unserialize() // 反序列化
魔术方法
魔术方法是计算机编程中的一个概念,用于描述如何在特定条件下自动执行某些代码或操作(例如:构造函数、析构函数等)。
在PHP中,魔术方法常用__开头
常见的反序列化函数
PHP反序列化
原理
未对用户输入的反序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行、SQL注入、目录遍历等不可控后果。在反序列化的过程中自动触发了某些魔术方法,当进行反序列化的时候就有可能会触发对象中的一些魔术方法。
换句话说:攻击者可以自由控制反序列化字符串(指的是反序列化函数接收一个变量,而该变量可由攻击者控制),构造payload,修改对象的状态,当payload被反序列化时,会生成一个恶意对象,当调用该对象的方法时(有可能会调用魔术方法),就会造成攻击。
反序列化漏洞一般黑盒探测不到,都是在白盒下进行测试(直接寻找特定函数即可)。
反序列化的利用
- 魔术方法的调用逻辑(如触发条件)
- 语言原生类的调用逻辑(如SoapClient)
- 语言自身的安全缺陷(如CVE-2016-7124)
PHP常用的魔术方法
注:__CALL魔术方法:调用某个方法,若方法存在,则直接调用,若不存在,则会去调用__CALL函数
注:__GET魔术方法:读取一个对象的属性时,若属性存在,则直接返回属性值,若不存在,则会调用__get函数
注:__SET魔术方法:设置一个对象的属性时,若属性存在,则直接赋值,若不存在,则会调用__set函数
注:__SLEEP魔术方法:serialize之前被调用,可以指定要序列化的对象属性
注:__WAKEUP魔术方法:反序列化恢复对象之前调用该方法
注:__ISSET魔术方法:检测对象的某个属性是否存在时执行此方法。当对不可访问属性调用isset()或empty()时,会调用__isset方法。
注:__UNSET魔术方法:在不可访问的属性上使用unset()时触发,销毁对象的某个属性时执行该函数。
注:值得注意的是:unset()函数不光可以销毁属性,更可以销毁对象
注:__INVOKE魔术方法:将对象当作函数来使用时执行此方法,通常不推荐这样做
对象属性权限
- public:在本类内部、外部类、子类都可以访问。
- protect:只有本类或子类或父类中可以访问
- private:只有本类内可以使用
这些权限在序列化的时候,数据显示有些差别:
private属性序列化的时候格式是%00类名%00成员名,%00不会显示,但是长度为1。
protect属性序列化的时候格式是%00*%00成员名。
注:这种特性使得:在构造payload的时候,除特殊情况外,一般都要将payload进行base64编码,如果不进行base64编码的话,诸如%00这样的字符是会被忽略,从而导致payload不正确的情况
PHP序列化/反序列化字符串分析
假设存在类demotest
class demotest{
public $name = 'xiaodi';
public $sex = 'man';
public $age = '29';
}
当对上述类的对象进行序列化后,序列化字符串为:
O:8:"demotest":3:{s:4:"name";s:6:"xiaodi";s:3:"sex";s:3:"man";s:3:"age";s:2:"29";}
解读:
- O标识Object,8表示类名长度,demotest为类名
- 3表示有三个成员
- s:4:"name";s:6:"xiaodi"; 代表:有一个string类型的成员名长度为4的成员,名字是name。这个成员有一个string类型的,长度为6的值,叫xiaodi。
- s:3:"sex";s:3:"man"; 代表:有一个string类型的成员名长度为3的成员,名字是sex。这个成员有一个string类型的,长度为3的值,叫man。
- s:3:"age";s:2:"29"; 代表:有一个string类型的成员名长度为3的成员,名字是age。这个成员有一个string类型的,长度为2的值,叫'29'。
当对上述类的对象进行反序列化后,序列化字符串为:
object(demotest)#2 (3) { ["name"]=> string(6) "xiaodi" ["sex"]=> string(3) "man" ["age"]=> string(2) "29" }
注:在上述的序列化字符串中我们可以看到:字符串中没有记录任何方法和魔术方法的信息,因此当我们进行构造payload的时候,可控点只有变量,方法是不可控的
注:换句话来说:在php反序列化的过程中,可控点只有变量,方法不可控
POP链构造
见CTF-Show-反序列化系列
原生类反序列化
见CTF-Show-反序列化系列、BUUCTF-极客大挑战2019-PHP
文章:
- https://www.cnblogs.com/iamstudy/articles/unserialize_in_php_inner_class.html
- https://blog.csdn.net/JSPSEO/article/details/125135112
- https://blog.csdn.net/qq_41517071/article/details/100974511
- php常用的原生类反序列化:https://www.anquanke.com/post/id/264823
- php原生类的反序列化应用:https://dar1in9s.github.io/2020/04/02/php/php原生类的利用/
如果在代码审计中存在反序列化的点,但是在原本的代码中找不到可利用的类时,可以考虑使用php中的一些原生类(php内部自带的类)。
有些原生类不一定能够进行反序列化,php中使用了zend_class_unserialize_deny来禁止一些类的反序列化。
我们可以通过脚本获取php中所有的原生类:
<?php
$classes = get_declared_classes();
foreach ($classes as $class) {
$methods = get_class_methods($class);
foreach ($methods as $method) {
if (in_array($method, array(
'__destruct',
'__toString',
'__wakeup',
'__call',
'__callStatic',
'__get',
'__set',
'__isset',
'__unset',
'__invoke',
'__set_state' // 可以根据题目环境将指定的方法添加进来, 来遍历存在指定方法的原生类
))) {
print $class . '::' . $method . "\n";
}
}
}
Java反序列化
原理
跟PHP相似,如果攻击者可以自由的控制序列化后的字符串,那么在进行反序列化后,调用恶意对象时就会造成攻击。
Java反序列化所产生的地方
反序列化操作一般应用在导入模板文件、网络通信、数据传输、日志格式化存储、对象存储在磁盘或数据库存储等业务场景。因此,审计过程中要重点关注这些业务。
具体细节:
Java序列化/反序列化字符串特征
一段数据以rO0AB开头,你基本可以确定这串就是JAVA序列化BASE64加密的数据。或者如果以aced开头,那么他就是这一段JAVA序列化的16进制。
最好通过诸如c32asm这样的工具去查看。
Java反序列化字符串构造/利用
通过ysoserial、GUI_TOOLS等工具,来进行构造,具体使用方法,请参考官方手册。
ysoserial:https://github.com/frohoff/ysoserial
具体的案例,可以参考Webgoat专题。
Java序列化/反序列化字符串分析
我们可以使用诸如SerializationDumper这类的工具,来对Java反序列化字符串进行分析。
这个工具经常用来分析Payload的构造。
SerializationDumper:https://github.com/NickstaDB/SerializationDumper/tree/master
黑盒/白盒测试
- 黑盒:从常见的功能点上观察,看交互的数据是否满足Java反序列化字符串的格式。
- 白盒:第三方插件安全(利用已知的第三方插件的漏洞)& Java特定反序列化函数搜索 & 找应用的特定功能
Python反序列化
原理
跟PHP相似,如果攻击者可以自由的控制序列化后的字符串,那么在进行反序列化后,调用恶意对象时就会造成攻击。
反序列化函数
注:除了这些函数之外,还有:marshal、PyYAML、shelve、PIL、unzip
魔术方法
POP链构造
见BUUCTF-CISCN2019华北赛区-ikun
注:与php反序列化不同,python反序列化POP链可以任意构造,可控点不只是变量,方法,类都可以。
注:如果存在漏洞的服务器,python版本是A,那么你在构造POP链的时候,使用的Python版本也得是A,一定要对应起来。
自动化审计工具bandit
对于python反序列化漏洞,在白盒测试的时候,我们可以搜索特定函数关键字,来进行审计。
黑盒测试一般测不到此漏洞。
或者,我们也可以使用工具来进行审计。
bandit的文档:https://bandit.readthedocs.io/en/latest/
安装bandit
pip install bandit
致谢
https://www.bilibili.com/video/BV1pQ4y1s7kH/?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click
免责声明
本博客中的内容仅供学习之用,不用于商业用途,也不可以用于任何非法用途,否则后果自负,本人不承担任何责任!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现