这里感觉自己想总结全部反序列化知识托大了,还是太菜了,于是就挑一些自己能写的总结一下吧。顺便贴上真大佬的学习链接
目录
一.简介
其实反序列化就是将原本已经序列化的数据反推回原来的数据,而在这里unserialize()和serialize()函数就是最重要的部分。举一个例子,有一个数组包含三个元素li men zzz 在序列化后就会成为
a:3{i:0;s:2:"li";i:1;s:3:"men";i:2;s:3:"zzz";}
在这里a表示数组类型,后面的3表示有3个属性(数组下标,字符串长度,字符串内容);
大括号里的i代表为整型,0表示数组下标为0;
s表示为是字符串类型,2表示字符串长度为2,“li”表示字符串内容,以此类推后两个元素。
反序列化后就会变成
Array
(
[0] => li
[1] => men
[2] => zzz
)
而此时若在变量前加上protect或private那么在进行序列化时会加上\x00*\x00或\x00类名\x00,这两个都是不可见字符,因此在输出给用户时会消失。这个暂时还没发现有什么地方可以用到。
二.反序列化常见魔术方法
__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发
魔术方法可以用来进行一些攻击,因为某些方法会对攻击有一定提示。
三.常见反序列化绕过方法
_wakeup()绕过方法
序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行
也就是说只要扩大对象属性个数,那么就可以执行反序列化
unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');在执行的时候会被__ wakeuo()干扰
但是如果改为unserialize('O:4:"test":2:{s:1:"a";s:3:"abc";}');就可以绕过__wakeup()来成功输出abc
正则匹配绕过方法
这个我熟,上一篇学了正则匹配举个例子
preg_match('/^O:\d+/')过滤了以O:开头的语句,但是此时通过改+号来绕过
$b = str_replace('O:4','O:+4', $a);
就可以绕过正则匹配。
看了大佬wp发现还有其他绕过
利用引用
public function __construct(){
$this->a = 'abc';
$this->b= &$this->a;
}
这里a与b的值相同,如果对a有过滤,可以对b进行构造。
十六进制绕过
O:4:"test":2:{s:4:"%00*%00a";s:3:"abc";s:7:"%00test%00b";s:3:"def";}
可以写成
O:4:"test":2:{S:4:"\00*\00\61";s:3:"abc";s:7:"%00test%00b";s:3:"def";}
表示字符类型的s大写时,会被当成16进制解析。
$a = 'O:4:"test":1:{S:8:"\\75sername";s:5:"admin";}'
php反序列化字符溢出逃逸
情况一
比如在php中,有str_replace函数如果将某个字符替换为多个字符,那么就会造成字符串溢出,比如:str_replace("x","xx",$str)这一函数把x替换成xx,就会导致反序列化出错,因为字符长度与序列化后的显示长度不同。而通过这个方法,可以使得逃逸的字符成功反序列化。例如输入name=maoxxxxxxxxxxxxxxxxxxxx";i:1;s:6:"woaini";},因为把一个x替换成了两个x于是多出的20个x顶掉了后面的;i:1;s:6:"woaini";},又因为有"闭合了前面的语句,于是打印出了woaini。
情况二
与情况一相反,这里是将多个字符替换为较少个字符。
总结
感觉反序列化的知识还是有点多的,不可能一下子总结完,还有很多知识还不是非常熟练,于是先暂时写到这里。下一次做几道例题再进行第二次总结。