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

Как я могу использовать PHP различные библиотеки XML, чтобы получить DOM-подобные функции и избежать DoS-уязвимостей, таких как Billion Laughs или Quadratic Blowup?

Я пишу веб-приложение с XML-API на PHP, и меня беспокоят три специфические уязвимости, связанные с встроенными определениями DOCTYPE: локальное включение файлов, разложение квадратичных объектов и разложение экспоненциальной сущности. Мне бы хотелось использовать встроенные библиотеки PHP (5.3), но я хочу убедиться, что я не восприимчив к ним.

Я обнаружил, что могу исключить LFI с помощью libxml_disable_entity_loader, но это не помогает с встроенными объявлениями ENTITY, включая объекты, которые ссылаются на другие объекты.

Библиотека SimpleXML (SimpleXMLElement, simplexml_load_string и т.д.) великолепна, потому что DOM-парсер и все мои входы довольно малы; он позволяет мне легко использовать xpath и манипулировать DOM. Я не могу понять, как остановить объявления ENTITY. (Я был бы рад отключить все встроенные определения DOCTYPE, если это возможно.)

Библиотека XML Parser (xml_parser_create, xml_set_element_handler и т.д.) позволяет мне установить обработчик по умолчанию, который включает сущности, с xml_set_default_handler. Я могу взломать его для непризнанных объектов, он просто возвращает исходную строку (т.е. "& Ent;" ). Однако эта библиотека разочаровывает: потому что это SAX-парсер, я должен написать кучу обработчиков (целых 9..).

Так можно ли использовать встроенные библиотеки, получить объекты, подобные DOM, и защитить себя от этих различных уязвимостей DoS? спасибо

Эта страница описывает три уязвимости и предоставляет решение... если бы я использовал .NET: http://msdn.microsoft.com/en-us/magazine/ee335713.aspx

UPDATE:

<?php
$s = <<EOF
<?xml version="1.0?>
<!DOCTYPE data [
<!ENTITY en "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....">
]>
<data>&en;&en;&en;&en;&en;&en;&en;&en;&en;&en;&en;&en;.....</data>
EOF;
$doc = new DOMDocument();
$doc->loadXML($s);
var_dump($d->lastChild->nodeValue);
?>

Я попробовал loadXML($s, LIBXML_NOENT);. В обоих случаях я заканчиваю сброс 300+ МБ. Есть что-то, чего я еще не вижу?

4b9b3361

Ответ 1

Примечание. Если вы создаете тестовые файлы с файлами, содержащими фрагменты XML, в следующем, ожидайте, что редакторы также будут подвержены этим атакам и могут зависнуть/сбой.

Миллиард смеха

<?xml version="1.0"?>
<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
  <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
  <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
  <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
  <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
  <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
  <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

При загрузке:

FATAL: # 89: обнаружен контур ссылки объекта 1: 7
... (плюс шесть раз то же = семь раз вместе с выше)
FATAL: # 89: обнаружен цикл ссылки сущности 14:13

Результат:

<?xml version="1.0"?>

Использование памяти светлое, пик не коснулся DOMDocument. Поскольку этот пример показывает 7 фатальных ошибок, можно заключить, и действительно, это так, что это загружает без ошибок:

<?xml version="1.0"?>
<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
]>
<lolz>&lol2;</lolz>

Поскольку подстановка объекта не действует и эта работа, попробуйте с

Квадратичная развязка

Вот здесь, укороченный для удовольствия от просмотра (мои варианты около 27/11kb):

<?xml version="1.0"?>
<!DOCTYPE kaboom [
  <!ENTITY a "aaaaaaaaaaaaaaaaaa...">
]>
<kaboom>&a;&a;&a;&a;&a;&a;&a;&a;&a;...</kaboom>

Если вы используете $doc->loadXML($src, LIBXML_NOENT);, это работает как атака, в то время как я пишу это, script по-прежнему загружается.... Так что на самом деле требуется некоторое время для загрузки и потребления памяти. Что-то вы можете играть сами. W/o LIBXML_NOENT работает безупречно и быстро.

Но есть оговорка, если вы, например, получаете nodeValue тега, вы получите расширения объектов, даже если вы не используете этот флаг загрузки.

Обходной путь для этой проблемы - удалить DocumentType node из документа. Обратите внимание на следующий код:

$doc = new DOMDocument();
$doc->loadXML($s); // where $s is a Quadratic attack xml string above.
// now remove the doctype node
foreach ($doc->childNodes as $child) {
    if ($child->nodeType===XML_DOCUMENT_TYPE_NODE) {
        $doc->removeChild($child);
        break;
    }
}
// Now the following is true:
assert($doc->doctype===NULL);
assert($doc->lastChild->nodeValue==='...');
// Note that entities remain unexpanded in the output XML
// This is not so good since this makes the XML invalid.
// Better is a manual walk through all nodes looking for XML_ENTITY_NODE
assert($doc->saveXML()==="<?xml version="1.0"?>\n<kaboom>&a;&a;&a;&a;&a;&a;&a;&a;&a;...</kaboom>\n");
// however, canonicalization will produce warnings because it must resolve entities
assert($doc->C14N()===False);
// Warning will be like:
//    PHP Warning:  DOMNode::C14N(): Node XML_ENTITY_REF_NODE is invalid here 

Итак, хотя это обходное решение помешает XML-документу потреблять ресурсы в DoS, это упрощает создание недопустимого XML.

Некоторые цифры (я уменьшил размер файла, в противном случае это займет слишком много времени) (code):

LIBXML_NOENT disabled                                          LIBXML_NOENT enabled

Mem: 356 184 (Peak: 435 464)                                   Mem: 356 280 (Peak: 435 464)                             
Loaded file quadratic-blowup-2.xml into string.                Loaded file quadratic-blowup-2.xml into string.          
Mem: 368 400 (Peak: 435 464)                                   Mem: 368 496 (Peak: 435 464)                             
DOMDocument loaded XML 11 881 bytes in 0.001368 secs.          DOMDocument loaded XML 11 881 bytes in 15.993627 secs.   
Mem: 369 088 (Peak: 435 464)                                   Mem: 369 184 (Peak: 435 464)                             
Removed load string.                                           Removed load string.                                     
Mem: 357 112 (Peak: 435 464)                                   Mem: 357 208 (Peak: 435 464)                             
Got XML (saveXML()), length: 11 880                            Got XML (saveXML()), length: 11 165 132                  
Got Text (nodeValue), length: 11 160 314; 11.060893 secs.      Got Text (nodeValue), length: 11 160 314; 0.025360 secs. 
Mem: 11 517 776 (Peak: 11 532 016)                             Mem: 11 517 872 (Peak: 22 685 360)                       

Я пока не думал о стратегиях защиты, но теперь знаю, что загрузка миллиарда смеется в PHPStorm заморозит его, например,, и я прекратил тестирование позже так как я не хотел его замораживать при написании этого.

Ответ 2

Фактически вы должны проверить свое приложение с образцовыми документами и посмотреть, уязвим ли он.

В основе библиотеки php xml лежит библиотека libxml2. Это поведение контролируется с php в основном через необязательные константы, которые большинство библиотек принимают в качестве аргумента при загрузке xml.

Вы можете определить версию php libxml2 с помощью echo LIBXML_DOTTED_VERSION;

В более поздних версиях (после версии 2.6) libxml2 содержит ограничения замещения сущности, предназначенные для предотвращения как экспоненциальных, так и квадратичных атак. Они могут быть переопределены с помощью опции LIBXML_PARSEHUGE.

По умолчанию libxml2 не загружает dtd, не добавляет атрибуты по умолчанию или не выполняет замещение сущности. Поэтому поведение по умолчанию - игнорировать dtds.

Вы можете включить части этого так:

  • LIBXML_DTDLOAD загрузит dtds.
  • LIBXML_NONET отключит сетевую загрузку dtds. Вы всегда должны иметь это и использовать каталог libxml dtd для загрузки dtds.
  • LIBXML_DTDVALID будет выполнять проверку dtd во время разбора.
  • LIBXML_NOENT будет выполнять замещение сущности.
  • LIBXML_DTDATTR добавит атрибуты по умолчанию.

Таким образом, использование настроек по умолчанию PHP/libxml2, вероятно, не уязвимы ни для одной из этих проблем, но единственный способ узнать наверняка - проверить.