Разъяснения по уязвимостям XXE во всех версиях PHP

Я размещаю здесь вопрос в качестве крайней меры, я просмотрел веб-страницы и прошел множество попыток, но не смог.

Репликация атаки XXE – это то, что я пытаюсь сделать, чтобы предотвратить их, но я не могу понять, как работает PHP с объектами XML. Для записи я использую PHP 5.5.10 на Ubuntu 12.04, но я провел несколько тестов на 5.4 и 5.3, а libxml2, похоже, имеет версию 2.7.8 (которая, похоже, не включает дефолт по умолчанию, чтобы не разрешать сущности).

В следующем примере вызов функции libxml_disable_entity_loader () с true или false не имеет никакого эффекта, или я делаю что-то неправильно.

$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?

Большое спасибо!

Рекомендации:

  • 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
  • Как я могу использовать различные XML-библиотеки PHP для получения DOM-подобных функций и предотвращения уязвимостей DoS, таких как Billion Laughs или Quadratic Blowup?

Держать его просто. Как должно быть просто 🙂

Ваш первый фрагмент кода

libxml_disable_entity_loader делает или ничего не делает здесь, исходя из того, решает ли ваша система по умолчанию или нет (мой не работает). Это контролируется опцией LIBXML_NOENT для libxml.

Без него процессор документов может даже не попробовать переводить внешние объекты, и поэтому libxml_disable_entity_loader имеет никакого 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 на внешний:

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

Тем не менее, на него могут влиять, например. allow_url_fopen PHP INI – установите значение false, и PHP никогда не загрузит удаленный файл.

Ваш третий фрагмент кода

Объект XML, который вы предоставили, не является внешним, а скорее внутренним (см., Например, здесь ).

Ваше лицо:

 <!ENTITY c "Blah blah"> 

Как определяется внутренняя сущность:

 <!ENTITY % name "entity_value"> 

Поэтому нет никаких оснований для PHP или libxml для предотвращения разрешения такой сущности.

Вывод

Я быстро установил скрипт PHP XXE, который проверяет различные настройки и показывает, успешна ли XXE и в этом случае.

Единственной строкой, которая должна фактически показывать предупреждение, является «LIBXML_NOENT».

Если какая-либо другая линия загружает WARNING, external entity loaded! ваша настройка позволяет загружать внешние объекты по умолчанию.

Вы не можете ошибаться, используя SHOULD USE libxml_disable_entity_loader () независимо от настроек вашего компьютера по умолчанию вашего поставщика. Если ваше приложение когда-либо будет перенесено, оно может стать уязвимым мгновенно.

правильное использование

Как MediaWiki заявляет в ссылке, которую вы опубликовали .

К сожалению, способ, которым 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)! 

Возможно, это связано с этой ошибкой PHP, но PHP действительно глупо об этом:

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

работает просто отлично.