序列化和反序列化本身没有问题,但是如果反序列化的1.内容是用户可以控制的,且后台2.不正当的使用了PHP中的魔法函数,就会导致安全问题。当传给unserialize()的3.参数可控时,可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。
存在漏洞的思路:一个类用于临时将日志储存进某个文件,当__destruct被调用时,日志文件将会被删除:
Class logdata
Class User
构造POC输入删除目录下的index.php文件:
请记住,序列化他只序列化属性,不序列化方法
在我们的利用中,反序列化函数只要这个参数可控,我们就能传入任何的已经序列化的对象(只要这个类在当前作用域存在我们就可以利用),而不是局限于出现,如果只能局限于当前类,那我们的利用面也太狭小了,这个类不调用危险的方法我们就没法发起attack。
0x06 PHP反序列化高阶学习(Php phar / PHP POP 链)
POP 链的介绍:
ROP 的全称是面向返回编程(Return-Oriented Programing),ROP 链构造中是寻找当前系统环境中或者内存环境里已经存在的、具有固定地址且带有返回操作的指令集,将这些本来无害的片段拼接起来,形成一个连续的层层递进的调用链,最终达到我们的执行 libc 中函数或者是 systemcall 的目的
POP 面向属性编程(Property-Oriented Programing) 常用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链,最终达到hacker邪恶的目的
说的再具体一点就是 ROP 是通过栈溢出实现控制指令的执行流程,而我们的反序列化是通过控制对象的属性从而实现控制程序的执行流程,进而达成利用本身无害的代码进行有害操作的目的
说了这么多理论了,来点实战性的东西演示一下 POP 链的形成吧!
现在我们就按照,我上面说的步骤来一步一步的分析这段代码,最终构造我们的 POP 链完成利用
(1)寻找 unserialize() 函数的参数是否有我们的可控点
我们假设已经在第一段代码里设置了参数可控的 unserialize()
(2)寻找我们的反序列化的目标,重点寻找 存在 wakeup() 或 destruct() 魔法函数的类
我们在第一段代码中寻找,我们发现一眼就看到了我们最想要看到的东西,__destruct() 魔法方法,好,既然这样我们就将这个类作为我们的漏洞嫌疑对象
(3)一层一层地研究该类在魔法方法中使用的属性和属性调用的方法,看看是否有可控的属性能实现在当前调用的过程中触发的
1.我们就先来看一下这个 $write ,这个 $write 虽然不是属性,但是他是我们 $_write 属性的其中一部分,那么控制他也就等于控制属性,那我们就要好好研究一下这个 $write 了,他是什么呢?通过他能调用 shutdown() 来看,他是某一个类的一个对象,因为他不是单纯的属性所以我们还要向下挖
2.于是我们就要找一下定义 shutdown() 方法的类,然后我们就锁定了 Zend_Log_Writer_Mail 这个类,我们看到这个类里面使用了 $write 对象的很多属性,比如说 _layout ,然后我们又发现这个属性也调用了一个方法 render() ,说明这个属性其实也是一个对象,于是我们还要向更深处挖掘
3.那么 _layout 是谁的对象呢?我们发现他是 Zend_layout 的一个对象,同样的,他里面是用了一个 _inflector 的属性,这个属性调用了 filter 方法,看来他也是一个对象(有完没完~~)别急,我们继续向下
4.我们发现 _inflector 是 Zend_Filter_PregReplace 的一个对象,这个对象的一些属性是能进行直接控制的,并且在调用 filter 方法的时候能直接触发 preg_replace() 方法,太好了这正是我们想要的,我们只要控制这个对象的属性就能实现我们的利用链
最后一张 图片实际上已经将整个利用链画了出来,并且给上了 payload ,下面我想通过对整个 payload 的分析再来回顾一下整个 POP 链的调用过程.
所以整个 POP 链就是
writer->shutdown()->render()->filter()->preg_replace(我们控制的属性)->代码执行
声明:
当然这是一个很老的但是很经典的例子,里面用到的方法还是 preg_replace() 的 /e 选项,我们只是学习使用,请大家不要纠结
利用 phar:// 拓展 PHP 反序列化的利用面
在 2017 年的 hitcon Orange 的一道 0day 题的解法令人震惊,Orange 通过他对底层的深度理解,为 PHP 反序列化开启了新的篇章,在此之后的 black 2018 演讲者同样用这个话题讲述了 phar:// 协议在 PHP 反序列化中的神奇利用,那么接下来就让我们分析他为什么开启了 PHP 反序列化的新世界,以及剖析一下这个他的利用方法。1.回顾一下原先 PHP 反序列化漏洞的必要条件
(1)首先我们必须有 unserailize() 函数
(2)unserailize() 函数的参数必须可控
这两个是原先存在 PHP 反序列化漏洞的必要条件,没有这两个条件你谈都不要谈,根本不可能,但是从2017 年开始 Orange 告诉我们是可以的
2.phar:// 如何扩展反序列化的利用面的
原来 phar 文件包在 生成时会以序列化的形式存储用户自定义的 meta-data ,配合 phar:// 我们就能在文件系统函数 file_exists() is_dir() 等参数可控的情况下实现自动的反序列化操作,于是我们就能通过构造精心设计的 phar 包在没有 unserailize() 的情况下实现反序列化漏洞利用,从而将 PHP 反序列化漏洞的触发条件大大拓宽了,降低了我们 PHP 反序列化的利用起点。
3.具体解释一下 phar 的使用
1.Phar 的文件结构
phar 文件最核心也是必须要有的部分如图所示: phar-1.png
(1) a stub
图片中说了,这其实就是一个PHP 文件实际上我们能将其复杂化为下面这个样子
格式为:
xxx
前面内容不限,但必须以__HALT_COMPILER();?>来结尾,这部分的目的就是让 phar 扩展识别这是一个标准的 phar 文件
(2)a manifest describing the contents
因为 Phar 本身就是一个压缩文件,它里面存储着其中每个被压缩文件的权限、属性等信息。这部分还会以序列化的形式存储用户自定义的meta-data,这是上述漏洞利用手法最核心的地方。
(3)the file contents
这部分就是我们想要压缩在 phar 压缩包内部的文件
2.如何创建一个合法的 Phar压缩文件 http://127.0.0.1/php_unserialize/Phar-1.php
可以清楚地看到我们的 TestObject 类已经以序列化的形式存入文件中
我们刚刚说过了,php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化
测试后受影响的函数如下: 受影响的函数列表
fileatime filectime file_exists file_get_contents
file_put_contents file filegroup fopen
fileinode filemtime fileowner fikeperms
is_dir is_executable is_file is_link
is_readable is_writable is_writeable parse_ini_file
copy unlink stat readfile
3.phar 反序列化小实验
<?php
class TestObject {
public function __destruct() {
echo 'Destruct called';
}
}
$filename = 'phar://phar.phar/test.txt';
file_get_contents($filename);
?>
可以看出我们成功的在没有 unserailize() 函数的情况下,通过精心构造的 phar 文件,再结合 phar:// 协议,配合文件系统函数,实现了一次精彩的反序列化操作。
其他函数当然也是可行的:
phar_test2.php
当文件系统函数的参数可控时,我们可以在不调用unserialize()的情况下进行反序列化操作,一些之前看起来“人畜无害”的函数也变得“暗藏杀机”,极大的拓展了利用面。
实际利用
3.1 利用条件
任何漏洞或利用手法不能实际利用,都是纸上谈兵。在利用之前,先来看一下这种利用的利用条件。
phar文件要能够上传到服务器端。
要有可用的魔术方法作为“跳板”。
文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。
标签:PHP,函数,phar,漏洞,思路,序列化,我们,属性
From: https://blog.51cto.com/u_15854462/7178489