pikachu之php反序列化
一、php对象和类
php面向对象编程:
对象:可以做一些事情。一个对象有状态、行为和标识三种属性。
类:一个共享共同结构和行为的对象的集合。
每个类的定义都以class开头,后面跟着类的名字,一个类可以包含有属于自己的变量,变量(称为属性)以及函数(称为方法)。类定义了一件事物的抽象特点。通常来说,类定义了事物的属性和它可以做到的。
类可能包含一些特殊的函数(magic函数),magic函数命名是以符号‘_’开头的,比如_construct当一个队形创建时调用;_destruct当一个对象被销毁时调用;_toString当一个对象被当作一个字符串时使用
__construct: 在创建对象时候初始化对象,一般用于对变量赋初值。 __destruct: 和构造函数相反,当对象所在函数调用完毕后执行。 __toString:当对象被当做一个字符串使用时调用。 __sleep: 序列化对象之前就调用此方法(其返回需要一个数组) __wakeup: 反序列化恢复对象之前调用该方法 __call: 当调用对象中不存在的方法会自动调用该方法。 __get: 在调用私有属性的时候会自动执行 __isset():在不可访问的属性上调用isset()或empty()时触发 __unset():在不可访问的属性上使用unset()时触发
例一:
例二:
二、php反序列化
在传递变量的过程中,有可能遇到变量值要跨脚本文件传递的过程。如果一个脚本中想要的调用之前一个脚本的变量,但是之前一个脚本已经执行完毕,所有的变量和内容释放掉了,那该如何操作呢?serialize和unserialize就是解决这一问题的存在,serialize可以将变量转换为字符串,并且在转换的过程中可以保存当前变量的值,而unserialize则可以将serialize生成的字符串转换回变量。通俗来说:通过反序列化在特定条件下可以重建php对象并执行php对象中某些magic函数。我们通过例子来看php对象序列化之后的格式,代码如下:
例一:
- 为什么会输出两次‘__destruct’呢?难道__destruct方法被调用了两次?也就是说脚本结束了两次?
来查查__destruct的具体用法:
原来就是脚本结束了两次,第一次是原本的object运行完毕时,第二次由于反序列化再次激活了对象object2随着脚本的运行结束也完毕了,所以相当于调用了两次__destruct方法,也就会输出两次"__destruct"。
-
看看反序列化的结果
O:4:"test":2:{s:8:"variable";s:4:"mdzz";s:9:"variable2";s:5:"other";}
O:代表Object
4:代表对象名长度为4
2:该对象中有两个变量
s:该变量为str型
8:该变量名长度为8
variable:该变量内容为variable
后面以此类推…
三、靶场演示
一般情况下,php反序列化漏洞是通过代码审计发现的。
所以我们直接上源码:
有源码可知,后台直接将用户的输入做反序列化,并调用其中的test属性,直接输出到p标签中
根据源码,编写poc
访问该页面:
查看网页源代码获取payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
在网页提交payload:
如图成功弹窗!
四、总结
反序列化(unserialize)漏洞依赖条件:
1、unserialize参数用户可控。
2、脚本的类中存在构造函数(__construct()、析构函数__destruct()、__wakeup()等),该构造函数中有向php文件中写数据的操作的类。
3、所写的内容需要有对象中的成员变量的值。
防范方法:
1、严控unserialize函数的参数。
2、对unserialize后的变量内容严格检查,以确保未被污染。