FMC*_*orz 16 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;
Run Code Online (Sandbox Code Playgroud)
但是,我可以专门将一些参数传递给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;
Run Code Online (Sandbox Code Playgroud)
现在,如果我们将实体更改为其他内容,如下例所示,实体已解析但我无法使用参数或函数禁用它...发生了什么?!
$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;
Run Code Online (Sandbox Code Playgroud)
我能找到的唯一方法是覆盖DOMDocument对象的属性.
然后他们会得到解决.
总而言之,我真的很想了解我显然不理解的东西.为什么这些参数和功能似乎没有效果?libxml2优先于PHP吗?
非常感谢!
参考文献:
保持简单..因为它应该很简单:-)
libxml_disable_entity_loader根据您的系统是否默认解析实体(我没有)来做或不做任何事情.这是由LIBXML_NOENTlibxml选项控制的.
没有它,文档处理器甚至可能不会尝试翻译外部实体,因此libxml_disable_entity_loader没有任何真正的影响(如果libxml默认情况下不加载实体,这在您的测试用例中似乎就是这种情况).
加入LIBXML_NOENT到loadXML()这样的:
$dom->loadXML($xml, LIBXML_NOENT);
Run Code Online (Sandbox Code Playgroud)
你会很快得到:
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 ...
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您已通过使用该LIBXML_NOENT选项启用实体解析,这就是它之后的原因/etc/passwd.
即使对于外部URL,该示例在我的机器上运行正常 - 我将其更改为外部URL,ENTITY如下所示:
<!ENTITY c PUBLIC "bar" "https://stackoverflow.com/opensearch.xml">
Run Code Online (Sandbox Code Playgroud)
然而,它甚至可能受到影响.allow_url_fopenPHP INI设置 - 将其设置为false并且PHP将不会加载远程文件.
您提供的XML实体不是外部实体,而是内部实体(请参见此处).
你的实体:
<!ENTITY c "Blah blah">
Run Code Online (Sandbox Code Playgroud)
如何定义内部实体:
<!ENTITY % name "entity_value">
Run Code Online (Sandbox Code Playgroud)
因此,PHP或libxml没有理由阻止解析此类实体.
我已经快速建立了一个PHP XXE测试器脚本,该脚本尝试不同的设置并显示XXE是否成功以及在哪种情况下.
应该实际显示警告的唯一一行是"LIBXML_NOENT".
如果任何其他行加载,则WARNING, external entity loaded!您的设置默认允许加载外部实体.
你不能去错用方可使用libxml_disable_entity_loader()不管你/你的供应商的机器默认设置.如果您的应用程序被迁移,它可能会立即变得脆弱.
正如MediaWiki在链接中所述,您已发布.
遗憾的是,libxml2实现禁用的方式是,当禁用外部实体时,库会被削弱,否则安全的函数会导致整个解析中出现异常.
$oldValue = libxml_disable_entity_loader(true);
// do whatever XML-processing related
libxml_disable_entity_loader($oldValue);
Run Code Online (Sandbox Code Playgroud)
注意: 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";
Run Code Online (Sandbox Code Playgroud)
在我的机器上:
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)!
Run Code Online (Sandbox Code Playgroud)
它可能与这个PHP错误有关,但PHP对它真的很愚蠢:
libxml_disable_entity_loader(true);
$dom->loadXML(file_get_contents($remote_xml));
Run Code Online (Sandbox Code Playgroud)
工作得很好.