PHP反序列化利用总结
序列化
来自PHP官方文档的解释,所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
魔术方法
PHP 将所有以\(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以__ 为前缀。
详细参考官方文档
序列化结构分析
1、含义
eg:O:4:"user":2:{s:3:"age";i:20;s:4:"name";s:7:"coco1er";}
O代表对象;4代表对象名长度;2代表2个成员变量;
其他结构参照:
类型 | 结构 |
---|---|
String | s:size:value; |
Integer | i:value; |
Boolean | b:value;(保存1或0) |
Array | a:size:{key definition;value definition;(repeated per element)} |
Null | N; |
Object | O:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)} |
2、结构实例
1 | string(5) "i:34;" |
3、public . protect . private下序列化对象的区别
public变量
直接变量名反序列化出来
private变量
\x00 + 类名+ \x00 + 变量名
protect变量
\x00 + * + \x00 + 变量名
反序列化利用
__wakeup失效
当序列化字符串中,如果表示对象属性个数的值大于真实的属性个数时就会跳过__wakeup()的执行
适用版本:
PHP5 < 5.6.25
PHP7 < 7.0.10
参考CVE-2016-7124
使用+
绕过正则
例:
1 | preg_match('/[oc]:\d+:/i', $var) O:4:"Demo":1:{s:10:"Demofile";s:16:"f15g_1s_here.php";}=======>O:+4:"Demo":1{s:10:"Demofile";s:16:"f15g_1s_here.php";} |
Phar反序列化
PHP带有很多内置URL风格的封装协议,可用于类似fopen()、copy()、file_exists()和fielsize()的文件系统函数。
phar文件
PHAR(PHP归档)文件是一种打包格式,通过将许多PHP代码文件和其他资源(例如图像,样式表等)捆绑到一个归档文件中来实现应用程序和库的分发。所有PHAR文件都使用.phar作为文件扩展名,PHAR格式的归档需要使用自己写的PHP代码。
phar文件有四部分构成:
a stub
可以理解为一个标志,格式为
xxx<?php xxx;__HALT_COMPILER();?>
,前期内容不限,但必须以__HALT_COMPILER();?>来结尾,否则phar扩展将无法识别其为phar文件。a manifest describing the contents
phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都存放在这一部分中。这部分将会以序列化的形式存储用户自定义的meta-data。
the file contents
被压缩文件的内容
[optional] a signature for verifying Phar integrity (phar file format only)
签名,放在文件末尾,目前支持的两种签名格式是MD5和SHA1。
phar://利用点
漏洞触发点在使用phar://协议读取文件的时候,文件内容会被解析成phar对象,然后phar对象内的meta-data会被反序列化。
meta-data是用serialize()生成并保存在phar文件中,当内核调用phar_parse_metadata()解析meta-data数据时,会调用php_var_unserialize()对其进行反序列化操作,因此会造成反序列化漏洞。
PS:php.ini中必须设置phar.readonly=Off,不然Phar文件就会无法生成。
1 | <?php |
1 | <?php |
PS:系统文件操作的函数【如 file_exists(),fopen(),file_get_contents(),file() 等文件操作的函数】一般都能使用伪协议流,Phar:// 也是ok的
md5_file、filesize
拓展
Bzip / Gzip
如果 phar://不能出现在头几个字符怎么办?
1 | demo.php?filename=compress.bzip2://phar://upload_file/shell.gif/a |
or
1 | demo.php?filename=php://filter/read=convert.base64-encode/resource=phar://xxx |
绕过文件上传
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
file_un.php
1 |
|
利用代码
1 |
|
将生成的phar.phar改为phar.gif成功绕过上传,然后利用 file_exists,使用 phar://执行代码
Session反序列化
这个目前还没有刷到利用该知识点的题,后续遇上了再补上。可以参考
https://www.anquanke.com/post/id/159206#h2-10
参考: