Подтвердить что ты не робот

Разъяснения по уязвимостям 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?

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

Литература:

4b9b3361

Ответ 1

Сохранение простоты. Как это должно быть просто: -)

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

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

Без этого процессор документов может даже не попробовать переводить внешние сущности, и поэтому 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 тестер script, который пытается выполнить различные настройки и показывает, успешна ли 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);

Примечание. 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));

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