澄清了整个PHP版本中的XXE漏洞 [英] Clarifications on XXE vulnerabilities throughout PHP versions

查看:249
本文介绍了澄清了整个PHP版本中的XXE漏洞的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为最后的选择,我在这里发布了一个问题,我浏览了网络并进行了许多尝试,但没有成功.

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/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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆