澄清了整个PHP版本中的XXE漏洞 [英] Clarifications on XXE vulnerabilities throughout PHP versions
问题描述
作为最后的选择,我在这里发布了一个问题,我浏览了网络并进行了许多尝试,但没有成功.
I post a question here as a last resort, I have browsed the web and went through many attempts but did not succeed.
为了防止这种情况,我正在尝试复制XXE攻击,但是我似乎无法理解PHP与XML实体一起工作的方式.作为记录,我在Ubuntu 12.04上使用PHP 5.5.10,但是我已经在5.4和5.3上进行了一些测试,并且libxml2似乎是版本2.7.8(似乎不包括默认的不解析实体).
Replicating a XXE attack is what I am trying to do, in order to prevent them, but I cannot seem to get my head around the way PHP works with XML entities. For the record I am using PHP 5.5.10 on Ubuntu 12.04, but I have done some tests on 5.4 and 5.3, and libxml2 seem to be of version 2.7.8 (which does not seem to include the default to not resolving entities).
在以下示例中,使用true或false调用libxml_disable_entity_loader()无效,或者我做错了事.
In the following example, calling libxml_disable_entity_loader() with true or false has no effect, or I am doing something wrong.
$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时有效.
But, I could specifically pass some arguments to loadXML() to allow some options, and that works when the entity is a local file, not when it is an external 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;
现在,如果我们将实体更改为其他实体,如以下示例所示,实体已解析,但是我无法使用参数或函数完全禁用它...发生了什么事!!
Now if we are changing the entity to something else, as in the following example, the entity is resolved but I could not disable it at all using the parameters or function... What is happening?!
$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对象的属性.
The only way that I could find was to overwrite the properties of the DOMDocument object.
- resolveExternals设置为1
- substituteEntities设置为1
然后解决,否则解决.
总而言之,我真的很想了解我显然不了解的内容.为什么这些参数和功能似乎没有作用? libxml2是否优先于PHP?
So to summarise, I would really like to understand what I am obviously not understanding . Why do those parameters and function seem to have no effect? Is libxml2 taking precedence over PHP?
非常感谢!
参考:
- https://www.owasp.org/index.php/XML_External_Entity_% 28XXE%29_Processing
- http://au2.php.net/libxml_disable_entity_loader
- http://au2.php.net/manual/zh-CN/libxml. constants.php
- http://www.vsecurity.com/download/papers/XMLDTDEntityAttacks.pdf
- http://www.mediawiki.org/wiki/XML_External_Entity_Processing
- 如何使用PHP的各种XML库来获得类似DOM的功能并避免DoS漏洞(如Billion Laughs或Quadratic Blowup)?
- https://www.owasp.org/index.php/XML_External_Entity_%28XXE%29_Processing
- http://au2.php.net/libxml_disable_entity_loader
- http://au2.php.net/manual/en/libxml.constants.php
- http://www.vsecurity.com/download/papers/XMLDTDEntityAttacks.pdf
- http://www.mediawiki.org/wiki/XML_External_Entity_Processing
- How can I use PHP's various XML libraries to get DOM-like functionality and avoid DoS vulnerabilities, like Billion Laughs or Quadratic Blowup?
推荐答案
保持简单..因为它应该很简单:-)
Keeping it simple .. As it should be simple :-)
libxml_disable_entity_loader
根据系统默认情况下是否解析实体而执行任何操作(我的不是).这由libxml的LIBXML_NOENT
选项控制.
libxml_disable_entity_loader
does or does not do anything here based on whether your system resolves entities by default or not (mine does not). This is controlled by LIBXML_NOENT
option of libxml.
没有它,文档处理器甚至可能不会尝试翻译外部实体,因此libxml_disable_entity_loader
并没有什么真正的影响(如果libxml默认情况下不加载实体,这在您的测试用例中就是这种情况).
Without it the document processor may not even try translating external entities and therefore libxml_disable_entity_loader
has nothing to really influence (if libxml does not load entities by default which seems to be the case in your test-case).
像这样将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
之后.
Your second code snippet
In this scenario you've enabled entity resolving by using the LIBXML_NOENT
option, that's why it goes after /etc/passwd
.
即使对于外部URL,该示例在我的机器上也可以正常工作-我将ENTITY
更改为如下所示的外部URL:
The example works just fine on my machine even for external URL - I changed the ENTITY
to an external one like this:
<!ENTITY c PUBLIC "bar" "https://stackoverflow.com/opensearch.xml">
但是,它甚至可能受到例如的影响. allow_url_fopen
PHP INI设置-将其设置为false,PHP将永远不会加载远程文件.
It can, however, be even influenced by eg. allow_url_fopen
PHP INI setting - put it to false and PHP won't ever load a remote file.
XML实体不是外部实体,而是内部实体(请参见例如此处).
XML Entity that you've provided is not an external one but rather an internal one (see eg. here).
您的实体:
<!ENTITY c "Blah blah">
内部实体的定义方式
<!ENTITY % name "entity_value">
因此,PHP或libxml没有理由阻止解析此类实体.
Therefore there is no reason for PHP or libxml to prevent resolving such entity.
我已经快速建立了 PHP XXE测试脚本尝试不同的设置,并显示XXE是否成功以及在这种情况下.
I've quickly put up a PHP XXE tester script which tries out different settings and shows whether XXE is successful and in which case.
实际上应该显示警告的唯一一行是"LIBXML_NOENT".
The only line that should actually show a warning is the "LIBXML_NOENT" one.
如果有任何其他行加载WARNING, external entity loaded!
,则您的设置确实默认情况下允许加载外部实体.
If any other line loads the WARNING, external entity loaded!
your setup does allow loading external entities by default.
使用不会出错应该使用libxml_disable_entity_loader(),无论您/您的提供商的计算机默认设置如何.如果您的应用进行了迁移,它可能会立即变得脆弱.
You can't go wrong by using SHOULD USE libxml_disable_entity_loader() regardless of your/your provider's machine default settings. If your app ever gets migrated it might become vulnerable instantly.
正如MediaWiki在链接中指出的那样.
As the MediaWiki states in link you've posted.
不幸的是,libxml2实现禁用的方式,禁用了外部实体时库都被破坏了,否则本来可以安全的函数会在整个解析过程中引起异常.
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文件(而不是通过实体):
Note: libxml_disable_entity_loader() also prohibits loading external xml files directly (not through entities):
<?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)!
它可能与此PHP错误有关,但PHP确实是愚蠢的是:
It might perhaps be related to this PHP bug but PHP is being really stupid about it as:
libxml_disable_entity_loader(true);
$dom->loadXML(file_get_contents($remote_xml));
工作正常.
这篇关于澄清了整个PHP版本中的XXE漏洞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!