Я размещаю здесь вопрос в качестве крайней меры, я просмотрел веб-страницы и прошел множество попыток, но не смог.
Репликация атаки 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.
Затем они разрешаются или нет.
Итак, чтобы подвести итог, я бы очень хотел понять, что я, очевидно, не понимаю. Почему эти параметры и функции кажутся неэффективными? Является ли libxml2 приоритетом над PHP?
Большое спасибо!
Рекомендации:
Держать его просто. Как должно быть просто 🙂
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));
работает просто отлично.