PHP反序列化漏洞
前言:我写这个的目的主要是由于我在看题时看到了相关内容,处于新手期想要广泛获取知识,想由此激励自己学习php反序列化漏洞的相关知识,并总结学习心得与经验。
0.入坑题:攻防世界web(unserialize3)
ps:初见这题时我什么概念都不懂,整道题均由ds老师赞助完成(doge)
我们先由这道题引出相关内容吧:
题目给出了这个:
1 | class xctf{ |
除此之外没有什么东西,对新手来说大概率考的是payload的构造,因此有以下几个步骤:
第一步:理解你的类
1 | class xctf{ |
这个类有:
- 类名:
xctf(4个字符) - 一个公有属性:
flag,值为'111'
第二步:手动构造序列化字符串
A. 对象开始部分
对象以 O: 开头:
1 | O:类名长度:"类名":属性个数:{属性定义} |
O:表示对象4:类名长度(xctf是4个字符)"xctf":类名1:属性个数(这个类有1个属性){开始定义属性
B. 属性定义部分
公有属性的格式:s:属性名长度:"属性名";类型:值
属性 flag 是公有属性:
1 | s:4:"flag";s:3:"111"; |
s:4:"flag";属性名(flag是4个字符)s:3:"111";属性值(111是3个字符的字符串)
C. 闭合
1 | } |
第三步:完整序列化字符串
1 | O:4:"xctf":1:{s:4:"flag";s:3:"111";} |
而本题之所以能成功,是因为利用了_wakeup()的漏洞,当序列化字符串中的属性个数大于实际属性个数时,__wakeup() 不会执行。
从而构造URL:
1 | http://61.147.171.35:61068/?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";} |
进而得到flag。
小试牛刀后我们可以进一步思考这一方向的学习:
1.序列化和反序列化究竟是什么?
2.ds老师说的魔术方法具体是什么?
3.如何利用漏洞和绕过?
4.如何解决这些漏洞产生的安全问题?
带着这些问题我进入了学习:
一.序列化和反序列化
1.序列化serialize()
序列化是将对象或数组转化为字符串,方便储存,PHP使用serialize()函数将对象序列化,序列化只作用于对象的成员属性,不作用于成员方法(ps:类的内部构成分为成员属性和成员方法,或可称为变量和函数)
我们来看看序列化的代码:
1 | class S{ |
我们可以注意到,声明字段这里与例题都用的是public,除此之外还有protected和private。
其中,三者在序列化后的字符串表示区别如下:
1 | private变量会被序列化为:\x00类名\x00变量名 |
2.反序列化unserialize()
知道了序列化是什么,反序列化自然就是反着来,将字符串转化为对象,而反序列化漏洞,其实就是利用应用程序本身在反序列化过程中缺乏对传入数据有足够的验证和过滤,导致攻击者可以利用构造的恶意的序列化数据来执行攻击。
二.魔术方法详解
ps:谁取的名字,好抽象()
序列化和反序列化本身是正常的,但是如果用户可以控制反序列化的内容,并且PHP魔法函数使用不正当,就会产生漏洞,导致安全性问题。
1 | __construct() //类的构造函数,创建对象时触发 |
魔术方法的简单利用
1.__destruct()
1 | class Exploit { |
当反序列化时,若程序终止,__destruct()就会被触发,然后就会执行system。
2.__wakeup ()
前面提到了不再说。
3.__toString ()
1 | class FileReader { |
当攻击者能够控制filename属性时,可以通过反序列化该对象并将其转换为字符串,读取任意文件内容。
Leave a comment