PHP Deserialization
PHP 反序列化漏洞学习
PHP 反序列化漏洞学习
反序列化基础
- 序列化
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程
- JSON序列化
- PHP 序列化
各个字段的含义
O:4:"test":3:{s:10:"testflag";s:6:"Active";s:7:"*test";c;s:5:"test1";s:5:"test1";}
O=> 代表这是一个对象 4=> 对象名占四个字符(test) test => 对象名 3 => 对象有三个属性 s:10:“testflag” =>属性名 s:6:“Active” => 属性值 s:7:”*test” =>属性名 s:4:“test” => 属性值 s:5:“test1” =>属性名 s:5:“test1” => 属性值
Puiblic权限
该是几个字符就是几个字符
Private权限(私有权限)
.test.flag 因为是私有的,所以会在flag前加自己的类名,成为八个字符,前后两个%00,成为10个字符 私有属性序列化的时候格式是%00类名%00属性名
- Protected 权限属性
%00*%00属性名
- 反序列化
反序列化漏洞
- 魔术方法
我们只可以控制属性,却不可以控制方法,所以需要魔术方法在符合条件时触发
(1)construct():当对象创建时会自动调用(但在unserialize()时是不会自动调用的)。
(2)wakeup() :unserialize()时会自动调用
(3)destruct():当对象被销毁时会自动调用。
(4)toString():当反序列化后的对象被输出在模板中的时候(转换成字符串的时候)自动调用
(5)get() :当从不可访问的属性读取数据
(6)call(): 在对象上下文中调用不可访问的方法时触发
__toString触发条件
(1)echo ($obj) / print($obj) 打印时会触发 (2)反序列化对象与字符串连接时 (3)反序列化对象参与格式化字符串时 (4)反序列化对象与字符串进行==比较时(PHP进行==比较的时候会转换参数类型) (5)反序列化对象参与格式化SQL语句,绑定参数时 (6)反序列化对象在经过php字符串函数,如 strlen()、addslashes()时 (7)在in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串的时候toString会被调用 (8)反序列化的对象作为 class_exists() 的参数的时候
举例
利用 phar:// 拓展 PHP 反序列化的攻击面
原先条件
1.首先我们必须有 unserailize() 函数 2.unserailize() 函数的参数必须可控
phar文件结构
- a stub
前面内容随便,后面是固定的,表示一个标准的phar文件
xxx<?php xxx; __HALT_COMPILER();?>
- a manifest describing the contents
the file contents
这部分就是我们想要压缩在 phar 压缩包内部的文件
生成payload
创建一个合法的phar文件
<?php class TestObject { } @unlink("phar.phar"); $phar = new Phar("phar.phar"); //后缀名必须为phar $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub $o = new TestObject(); $phar->setMetadata($o); //将自定义的meta-data存入manifest $phar->addFromString("test.txt", "test"); //添加要压缩的文件 //签名自动计算 $phar->stopBuffering(); ?>
Tips
__wakeup
属性值大于原有属性数可以绕过
正则
if (substr($data, 0, 2) !== 'O:' && !preg_match('/O:\d:\/', $data))
代码对data进行了判断,不可以为对象,0:X,X不可以为数字,绕过方法可以使用array数组绕过第一个,在X前面加+绕过第二个限制,搭达到到达反序列化方法的步骤。在__destruct销毁时会调用createCache方法写入文件,达成目的。