我在这里发布一个问题作为最后的手段,我浏览了网页并经历了多次尝试,但没有成功。
复制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对象的属性。
然后他们得到了解决。
总而言之,我真的很想了解我显然不理解的东西。为什么这些参数和功能似乎没有效果? libxml2优先于PHP吗?
非常感谢!
参考文献:
答案 0 :(得分:8)
保持简单..因为它应该很简单: - )
libxml_disable_entity_loader
根据您的系统是否默认解析实体(我没有)来做或不做任何事情。这由libxml的LIBXML_NOENT
选项控制。
没有它,文档处理器甚至可能不会尝试翻译外部实体,因此libxml_disable_entity_loader
没有任何影响(如果libxml默认情况下不加载实体,这在您的测试用例中似乎就是这种情况)。 / p>
将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
之后的原因。
即使对于外部网址,该示例在我的计算机上运行正常 - 我将ENTITY
更改为外部网址:
<!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是否成功以及在哪种情况下。
唯一应该显示警告的行是&#34; LIBXML_NOENT&#34;之一。
如果任何其他行加载WARNING, external entity loaded!
您的设置默认允许加载外部实体。
使用不管您/您的提供商的计算机默认设置是否应该使用libxml_disable_entity_loader(),都可能出错。如果您的应用迁移了,它可能会立即变得脆弱。
正如MediaWiki在link you've posted中所述。
不幸的是,libxml2实现禁用的方式,当禁用外部实体时,库就会被削弱,否则安全的函数会导致整个解析中出现异常。
$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));
工作正常。