0x001 漏洞产生原理
在反序列化的过程中自动触发了某些魔术方法。未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致XSS、代码执行、文件写入、文件读取等不可控后果。
0x002 漏洞触发条件
一般只能通过代码审计的方式挖掘该漏洞,寻找代码中unserialize()函数的变量可控,且PHP文件代码中存在可利用的类,同时类中具有魔术方法。
0x003 PHP魔术方法__construct() 当一个对象创建时被调用
__destruct() 当一个对象销毁时被调用
__toString() 当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前运行
__wakeup 将在序列化之后立即被调用
0x004 序列化数据格式
序列化主要分为字符型、数组型、对象型。
以序列化对象格式为例
0x005 反序列化漏洞
1. XSS
漏洞示例demo2.php:
构造序列化值:
利用序列化值构造POC:
成功在页面进行了弹窗:在序列化数据之后,立即自动调用了__wakeup()函数,执行 。
2. 代码执行
漏洞示例test.php:
构造序列化值:
利用序列化值构造POC:
成功显示了phpinfo页面:在反序列化该数据时,自动触发了_destruct()函数,执行 eval(phpinfo())。
3. 文件写入
漏洞示例demo3.php:
构造序列化值:
利用序列化值构造POC:
成功将phpinfo写入了shell.php:在反序列化该数据结束后,,立即自动调用了__wakeup()函数,而在__wekeup()创建了对象后,就会自动调用__construct()函数,从而执行了文件写入的操作。
4. 文件读取
以2020 ISCC CTF中的一道题为例
代码审计
以GET形式传入一个data参数,并且对data参数进行了反序列化;
使用了_toString() 当一个对象被当作一个字符串时自动调用
使用file_get_contents()包含$file文件内容;
最后使用base64_encode()加密输出$file文件中的内容。
构造序列化值:
利用序列化值构造POC:
成功显示了flag.php文件中的内容:在反序列化该数据时,自动触发了_toString()函数,执行 base64_encode(file_get_contents($filename))。
5. 漏洞拓展
上面讲的都是基于魔术方法下的敏感操作导致的反序列化导致的安全问题。但是当漏洞/危险代码存在在类的普通成员方法中,该如何利用呢?
漏洞示例demo4.php:
我们发现类的普通方法调用eval()函数,这个函数很危险,如果可控就可能造成代码执行。
通过代码发现$_GET['test']可控,因为使用unserialize()会自动调用__destruct(),所以它会先调用action()函数,然后会走到x1类和x2类,而安全问题在x2类中。
构造如下序列化代码serialize-demo4.php:
上述序列化代码运行后得到的序列化值:
利用得到的序列化值构造POC:
0x006 反序列化webShell
1. 配合菜刀getShell
漏洞示例test.php:
利用eval()传入可控参数,写入一句话木马 <?php @eval($_GET[cmd]);?>,构造序列化数据值:
利用序列化值构造POC:
执行该POC后,会在同级目录下生成一个shell.php文件,通过菜刀连接访问shell.php,即可getShell。
2. 反序列化木马
利用反序列化的特点,编写webShell木马
使用菜刀连接该webShell木马
此木马与正常文件很像,所以对于免杀安全狗等防护软件效果很不错。
参考文章