php - 对整个 PHP 版本的 XXE 漏洞的澄清

标签 php xml security xxe

作为最后的手段,我在这里发布了一个问题,我浏览了网页并进行了多次尝试但没有成功。

复制 XXE 攻击是我试图做的,以防止它们,但我似乎无法理解 PHP 处理 XML 实体的方式。作为记录,我在 Ubuntu 12.04 上使用 PHP 5.5.10,但我在 5.4 和 5.3 上做了一些测试,libxml2 似乎是 2.7.8 版本(它似乎不包括不解析实体的默认值)。

在下面的示例中,使用 true 或 false 调用 libxml_disable_entity_loader() 没有任何效果,或者我做错了什么。

$xml = <<<XML
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY c PUBLIC "bar" "/etc/passwd">
]>
<root>
    <test>Test</test>
    <sub>&c;</sub>
</root>
XML;

libxml_disable_entity_loader(true);
$dom = new DOMDocument();
$dom->loadXML($xml);

// Prints Test.
print $dom->textContent;

但是,我可以专门将一些参数传递给 loadXML() 以允许一些选项,这在实体是本地文件而不是外部 URL 时有效。

$xml = <<<XML
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY c PUBLIC "bar" "/etc/passwd">
]>
<root>
    <test>Test</test>
    <sub>&c;</sub>
</root>
XML;

$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);

// Prints Test.
print $dom->textContent;

现在,如果我们将实体更改为其他实体,如下例所示,实体已解析,但我无法使用参数或函数完全禁用它...发生了什么?!

$xml = <<<XML
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY c "Blah blah">
]>
<root>
    <test>Test</test>
    <sub>&c;</sub>
</root>
XML;

$dom = new DOMDocument();
$dom->loadXML($xml);

// Prints Test.
print $dom->textContent;

我能找到的唯一方法是覆盖 DOMDocument 对象的属性。

  • resolveExternals 设置为 1
  • substituteEntities 设置为 1

然后他们就解决了,或者不解决。

总而言之,我真的很想理解我显然不理解的东西。为什么那些参数和功能似乎没有作用? libxml2 是否优先于 PHP?

非常感谢!

引用资料:

最佳答案

保持简单..因为它应该简单:-)

你的第一个代码片段

libxml_disable_entity_loader 在这里做或不做任何事情取决于你的系统是否默认解析实体(我的没有)。这由 libxml 的 LIBXML_NOENT 选项控制。

没有它,文档处理器甚至可能不会尝试翻译外部实体,因此 libxml_disable_entity_loader 没有任何真正的影响(如果 libxml 默认不加载实体,这在您的测试用例中似乎就是这种情况).

LIBXML_NOENT 添加到 loadXML() 中,如下所示:

$dom->loadXML($xml, LIBXML_NOENT);

你会很快得到:

PHP Warning:  DOMDocument::loadXML(): I/O warning : failed to load external entity "/etc/passwd" in ...
PHP Warning:  DOMDocument::loadXML(): Failure to process entity c in Entity, line: 7 in ...
PHP Warning:  DOMDocument::loadXML(): Entity 'c' not defined in Entity, line: 7 in ...

你的第二个代码片段

在这种情况下,您通过使用 LIBXML_NOENT 选项启用了实体解析,这就是它在 /etc/passwd 之后的原因。

该示例在我的机器上工作得很好,即使对于外部 URL - 我将 ENTITY 更改为这样的外部 URL:

<!ENTITY c PUBLIC "bar" "https://stackoverflow.com/opensearch.xml">

然而,它甚至会受到例如影响。 allow_url_fopen PHP INI 设置 - 将其设置为 false,PHP 将永远不会加载远程文件。

你的第三个代码片段

您提供的 XML 实体不是外部实体,而是内部实体(参见例如 here)。

您的实体:

<!ENTITY c "Blah blah">

内部实体是如何定义的:

<!ENTITY % name "entity_value">

因此,PHP 或 libxml 没有理由阻止解析此类实体。

结论

我很快就放了一个 PHP XXE tester script它尝试不同的设置并显示 XXE 是否成功以及在哪种情况下。

唯一应该实际显示警告的行是“LIBXML_NOENT”这一行。

如果任何其他行加载了 WARNING, external entity loaded! 您的设置默认允许加载外部实体。

无论您/您的提供商的机器默认设置如何,您使用都不会出错>应该使用 libxml_disable_entity_loader()。如果您的应用被迁移,它可能会立即变得易受攻击。

正确用法

正如 MediaWiki 在 link you've posted 中所述.

Unfortunately, the way that libxml2 implements the disabling, the library is crippled when external entities are disabled, and functions that would otherwise be safe cause an exception in the entire parsing.

$oldValue = libxml_disable_entity_loader(true);
// do whatever XML-processing related
libxml_disable_entity_loader($oldValue);

注意: libxml_disable_entity_loader() 也禁止直接加载外部 xml 文件(不通过实体):

<?php
$remote_xml = "https://stackoverflow.com/opensearch.xml";

$dom = new DOMDocument();

if ($dom->load($remote_xml) !== FALSE)
    echo "loaded remote xml!\n";
else
    echo "failed to load remote xml!\n";

libxml_disable_entity_loader(true);
if ($dom->load($remote_xml) !== FALSE)
    echo "loaded remote xml after libxml_disable_entity_loader(true)!\n";
else 
    echo "failed to remote xml after libxml_disable_entity_loader(true)!\n";

在我的机器上:

loaded remote xml!
PHP Warning:  DOMDocument::load(): I/O warning : failed to load external entity "https://stackoverflow.com/opensearch.xml" in ...
failed to remote xml after libxml_disable_entity_loader(true)!

可能与this PHP bug有关但是 PHP 对此非常愚蠢,因为:

libxml_disable_entity_loader(true);
$dom->loadXML(file_get_contents($remote_xml));

工作得很好。

关于php - 对整个 PHP 版本的 XXE 漏洞的澄清,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24117700/

相关文章:

php - 使用从 iOS 设备发送的 multipart/form-data 检索 HTTP POST 变量

php - 如果使用 PHP 为空,则在自定义字段周围隐藏 HTML

java - 如何在 Spring Boot 中从端点响应中全局省略空 xml 标签?

java - 限制对 Java Servlet 的访问

javascript - 有什么好的方法可以防止JavaScript多人游戏作弊?

security - 具有cloudera TLS故障的Kafka

java - android应用程序与网站数据库的连接

PHP 脚本无法从 Python 脚本获取输出

R XML - 将父节点和子节点组合成数据框

python - 如何使用 python lxml 通过 xslt 加速大型 xml 文件的转换