php反序列化漏洞

本文总结php的反序列化,有php反序列字符串逃逸,php反序列化pop链构造,php反序列化原生类的利用,phar反序列化,session反序列化,反序列化小技巧,并附带ctf小题来说明,还有php反序列化的预防方法(个人想法),建议按需查看,如有错误还望斧正。
如非特别说明运行环境为PHP 7.2.33-1+ubuntu18.04.1

为什么要序列化?

序列化可以将对象,类,数组,变量,匿名函数等,转换为字符串,这样用户就方便存储和传输,同时方便恢复使用,对服务器也减轻一定的压力。

序列化基础

序列化为字符串时候,变量和参数之间用;隔开,同一个变量和参数间用:号隔开,以}作为结尾,具体结构,用以下代码来看下结构

<?php class Lmg { public $name = 'Lmg'; public $age = 19; public $blog = 'https://lmg66.github.io'; } $lmg1 = new Lmg; echo serialize($lmg1)."\n"; ?>

php反序列化漏洞

序列化属性 在一个可以序列化的字符串后加其他参数不影响序列化后的结果

如:
测试代码:

<?php class Lmg { public $name = 'Lmg'; public $age = 19; public $blog = 'https://lmg66.github.io'; } $lmg1 = new Lmg; echo serialize($lmg1)."\n"; $Lmg2 = serialize($lmg1).'s:4:"blog";s:23:"https://lmg66.github.io";}'; echo $Lmg2."\n"; print_r($lmg1); print_r(unserialize($Lmg2)); ?>

效果:可以发现,后面加了其他参数并不影响序列化后的结果

php反序列化漏洞

显示变量长度和实际长度不匹配就会报错,在这里在某些情况就会产生字符串逃逸

如:
测试代码:

<?php class Lmg { public $name = 'Lmg'; public $age = 19; public $blog = 'https://lmg66.github.io'; } $lmg4 = 'O:3:"Lmg":3:{s:4:"name";s:3:"Lmg";s:3:"age";i:19;s:4:"blog";s:23:"https://lmg66.github.io";}'; $lmg5 = 'O:3:"Lmg":3:{s:4:"uname";s:3:"Lmg";s:3:"age";i:19;s:4:"blog";s:23:"https://lmg66.github.io";}'; print_r(unserialize($lmg4)); print_r(unserialize($lmg5)); ?>

效果:可以发现我改了变量名name使它的长度和实际4不符,就发生了报错,改其他类似

php反序列化漏洞

反序列常见魔术函数总览,可构造pop链 __construct: 当创建类的时候自动调用,也就是构造函数,无返回值 __destruct: 当类实例子销毁时候自动调用,也就是析构函数,无返回值,其不能带参数 __toString:当对象被当做一个字符串使用时调用,比如echo $obj 。 __sleep: 当类的实例被序列化时调用(其返回需要一个数组或者对象,一般返回对象的$this,返回的值被用来做序列化的值,如果不返回,表示序列化失败) __wakeup: 当反序列化时被调用 __call:当调用对象中不存在的方法会自动调用该方法。 __get:在调用私有属性的时候会自动执行 __isset()在不可访问的属性上调用isset()或empty()触发 __unset()在不可访问的属性上使用unset()时触发 反序列化字符串逃逸(替换后导致字符串变长)

字符串逃逸利用的是反序列化的属性如上文,出现原因是在序列化前进行了字符串的替换,导致字符串被拓冲,可以将后面的字符串挤出去,挤到后一个对象的变量从而改变其他的变量值,造成逃逸。
如:
测试代码:

<?php function filter($str){ return str_replace('bb', 'ccc', $str); } class A{ public $name='aaaa'; public $pass='123456'; } $AA=new A(); echo serialize($AA)."\n"; $res=filter(serialize($AA)); $c=unserialize($res); echo $c->pass; ?>

序列化后的字符串为:
O:1:"A":2:{s:4:"name";s:4:"aaaa";s:4:"pass";s:6:"123456";}
如果能让name变量的参数为
";s:4:"pass";s:6:"hack";}
用}号闭合掉后面的pass参数,就能改pass变量的参数值从而逃逸
要解决的就是这个位置的长度问题,只用读取到足够的长度,才会停止

php反序列化漏洞


可以发现在序列化进行了字符串的替换,但替换的时候bb替换成了ccc,也就是字符串变长了,达到我们上面想要的目的

php反序列化漏洞


先判断想要构造的字符串长度

<?php $lmg = '";s:4:"pass";s:6:"hack";}'; echo strlen($lmg)."\n"; // $lmg3 = "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"; // echo strlen($lmg3); // $lmg2 = "bb"; // echo str_repeat($lmg2, 25); ?>

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsgff.html