PHP反序列化漏洞

反序列化漏洞还是比较重要的 , PHP反序列化漏洞又被称为PHP对象注入 , 可能会导致远程代码执行( RCE )


PHP序列化与反序列化

要想了解PHP反序列化漏洞 , 首先要知道什么是PHP序列化

定义

PHP中所有的值都可以用函数 serialize() 返回的一个包含字节流的字符串来表示 , 序列化一个对象会保存当前对象的所有变量 , 会保留类的名字 , 但是不会保存对象的方法 . 如果序列化类A的一个对象 , 那么将返回一个和类A相关 , 并且包含该对象所有变量的字符串

PHP反序列化就是通过 unserialize() 重新把字符串变回原来的值 . 如果反序列化的变量为对象( Object ) , 那么在成功重构对象后PHP会自动调用 __wakeup()成员方法 .

简单的来说 , PHP序列化就是把代码中所有的 对象 , 类 , 数组 , 变量 , 匿名函数 ... 全部转换为一个字符串 , 提供给用户传输和存储 . 而反序列化就是把字符串重新转换为 对象 , 类 , 数组 , 变量 , 匿名函数 . 通过这种相互转换 ,从而完成 数据持久化

举个通俗易懂的例子吧

把`word`文档保存为`.docx`就是序列化操作 , 而打开`.docx`显示其中的内容 , 就是反序列化操作

几个比较重要的函数

  • __construct()
    在对象被创建时触发
  • __destruct()
    在对象被销毁时触发
  • __sleep()
    在对象被序列化之前触发
  • __wakeup()
    在对象被反序列化之前触发
  • __toString()
    当对象被当成字符串时触发
  • __get()
    当访问不可访问的属性时触发

看个demo

png

输出内容如下

png

上面这个代码初学者可能难以理解 , 来解释一下

$class = new test() : 生成一个实例对象 , 调用构造函数 __construct() , 这点没什么说的 . 大部分面向对象的语言都是这么做的

echo $class: 这里通过echo 把 对象$class 当做字符串输出 , 所以调用 __toString()

$str = serialize() : 序列化 对象$class . 把生成的字符串赋值给 $str , 在序列化之前先调用 __sleep() 方法来清理对象 , 并且返回一个包含对象中所有要被序列化的变量名称的数组

$new_class = unserialize($str) : 反序列化操作 , 将字符串重构成对象 . 在反序列化之前会调用 __wakeup() 方法来准备对象需要的资源 , 比如重新建立在序列化期间可能已丢失的任何数据库连接

当代码执行完毕后 , 会调用析构函数__destruct() , 销毁对象 , 因为这里生成了两个对象 , 所以析构函数会被执行两次

细心的人会发现 , 上面分别定义了三类变量 , 即 private $a , protected $b , public $c , 它们经过序列化后的字符串是有区别的

private
数据类型:属性名长度:"\00类名\00属性名";数据类型:属性值长度:"属性值"

protected
数据类型:属性名长度:"\00*\00属性名";数据类型:属性值长度:属性值

public
数据类型:属性名长度:属性名;数据类型:属性值长度:属性值

属性名上的区别在构造POC时十分关键!


PHP反序列化漏洞

通过上面的内容你应该对 PHP序列化与反序列化是个什么玩意儿 有一定理解了 , 那么到底什么是反序列化漏洞?

关于PHP反序列化漏洞 , 你需要知道以下几点
1. PHP序列化给我们传递对象提供了一种简单的方法 , 反序列化的数据本质上是没有危害的
2. 但是用户可控参数的反序列化数据是有危害的
3. 当用户利用魔术方法或者其他敏感函数进行恶意操作时 , 会出现安全问题

来看个demo , 你就能初步理解了

png

这个代码看起来没什么问题 , 但是别忘了unserialize() 前会先调用 __wakeup() 来准备资源 , 它们之间没有其他的过程 , 也就是说 , 通过控制序列化字符串就可以直接来触发__wakeup() 中的内容 .

当我们在访问下面这个url时 , 会直接在目标服务器生成一个 webshell !

http://127.0.0.1/test.php?string=O:4:%22Test%22:1:{s:1:%22a%22;s:29:%22%3C?php%20eval($_POST[shell]);%20?%3E%22;}

你可以尝试连接一下 ~ 轻松拿到shell ~

png

上面是用户恶意利用魔术方法中的漏洞 , 那么用户是否能利用普通成员方法中的漏洞呢?

当然是可能的 , 我们可以尝试寻找相同的函数名 , 把敏感函数和类联系起来 . 下面这个例子就是普通成员方法中的漏洞

png

一般的工程师看到上面这个代码肯定觉得没有什么风险 , 因为唯一存在风险的函数eval()并没有被执行 , 甚至连 class noob2 都没有被实例化

但是直觉往往是错的 , 他觉得它的代码无法调用 noob2 中的函数 , 不代表我们不可以 !

可以看到 class noob1class noob2 中都存在一个 action() 的同名函数 , 而 class noob2 中的 action() 函数可以执行 $test1 中的内容 , 所以可以想方法在 new noob() 时可以调用 class noob2 中的 action() 方法

我们构造一个反序列化字符串 , 这里拿 phpinfo 做demo

O:4:"noob":1:{s:4:"test";O:5:"noob2":1:{s:5:"test1";s:10:"phpinfo();";}}

访问指定url , 即可成功调用 class noob2 中的eval()函数

png


CVE-2016-7124

说到PHP反序列化漏洞 , 那就不得不提 CVE-2016-7124 , 该漏洞使得攻击者可以成功的绕过 __wakeup() 函数 .

影响版本:

PHP5 < 5.6.25

PHP7 < 7.0.10

简单的说 , 当序列化字符串中的设置的属性个数大于实际的属性个数时 , 对象属性检测就会出现异常 , 那么process_nested_data()就会返回0 , 反序列化产生异常 , 从而不执行 __wakeup() 函数 . 在此之前对象和它的属性已经被创建 , 但紧接着对象将被破坏 , 从而执行 __destruct() 函数 , 从而产生漏洞

png


PHP反序列化的问题我就暂时遇到这么多 , 以后如果遇到其他的题型再来写吧

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇