Введение:
Всех приветствую ! Сегодня, как и обещал в прошлой статье, поговорим об XML-инъекциях. Уязвимость достаточно сложная и требует неплохой теоретической базы. Поэтому я постараюсь рассказать те теоретические аспекты, которые необходимы для общего понимания, при этом не углубляясь в вещи, которые особо не нужны. Но если кто захочет более подробно разобраться в теме – по ходу статьи буду оставлять небольшие “подсказки” куда копать и куда смотреть ) Ну и естественно разберем как уязвимость искать, эксплуатировать, какой профит с нее можно поиметь, как автоматизировать некоторые процессы и т.д. А посмотреть там есть на что – это и локальное включение файлов, и Server Side Request Forgery, а если повезет, то и может RCE. Ну и несколько видов самих иньекций. Сразу предупреждаю – статья получилась достаточно обьемной, поэтому запасайтесь попкорном ) Поехали:
Теория – XML и API
Для более полного понимаю что такое XML-иньекции, нужно ознакомиться с двумя понятиями – что такое сам XML и как он связан с такой штукой как API. Это нужно для понимания того, как и где вообще веб-приложения связаны и работают с XML. Именно это я сейчас и постараюсь обьяснить:
XML
XML – с английского эта аббривиатура расшифровывается как eXtensible Markup Language, то есть расширяемый язык разметки. Есть большое количество языков, основаных именно на XML – например, XAML, который используется в WPF в .NET, и множество других языков для самых разных сфер деятельности – медицины, бухгалтерии и т.д. Даже векторный формат изображений SVG основан на XML и является языком разметки масштабируемой графики. Вообщем, XML – это золотой стандарт для языков разметки, который является прародителем многих современных языков.
Если вы знакомы с HTML, то примерно представляете как выглядит этот язык разметки. Но все же есть некоторые различия. Во первых, HTML используется для представления и отображения данных, а XML, в первую очередь, для их передачи. Да и появился html раньше.
Но во многом эти язки разметки похожи. Так же как html этот язык состоит из тегов и атрибутов к ним. Стандартная структура XML документа выглядит примерно вот так:
Первой строкой идет заголовок, в котором сообщается версия XML и кодировка
Далее следует так называемый “основной тег” или корень – главный тег, внутри которого находятся все остальные. Проводя аналогию с тем же html – там есть тег <html>, который являтся корневым. Здесь примерно то же самое, с тем отличием, что название тега определяет сам создатель – он зависит от того, какие данные будут хранится в документе.
В примере это тег - <cars>, который говорит о том, что в документе будет содержаться информация об автомобилях.
Ну и далее идет непосредственно содержимое документа в виде тегов и атрибутов – в примере это марка автомобиля и модель.
Вся эта структура вполне себе понятна и логична, особенно если вы знакомы с html.
Вторая важная деталь в XML, о которой нужно знать – внешние сущности (External entities). Что это вообще такое ?
Начнем сначала:
В документах XML может содержаться разная информация и ее нужно каким-то образом стандартизировать. Это нужно для удобства дальнейшей работы с документами. Как правило, для такой локальной стандартизации в документ подключается другой документ, который и содержит информацию о том, как XML-документ должен выглядеть. Для этого, используются два подхода: XSD (XML Schema Definition) и DTD (Document Type Definition) Нас здесь будет интересовать конктретно второй тип, поэтому остановимся на DTD.
Для такой стандартизации используется сторонний документ формата .dtd, который и содержит информацию о том, какие теги и какие значения должны содержаться в документе. Сам файл типа .dtd нас не особо интересует, куда более интересно как такие файлы связываются с документами, которые они стандартизируют.
А связываются они так:
Создается тег Document Type Declaration, который выглядит следующим образом:
По аналогии, в html документы подобным образом подключаются, например, стили CSS, или скрипты написаные на JavaScript.
Но это не самое интересное. Дело в том, что в формате DTD есть еще такая вещь, как сущности. Сущности нужны в первую очередь для того, чтобы подключать в документ часто используемые фрагменты XML. Достаточно удобно, чтобы не переписывать одно и то же, можно просто добавить строку следующего вида:
Где name – имя сущности, a path – путь к содержимому. Далее второй строкой, уже где-то в теле корневого тега, сущность необходимо “вызвать” по аналогии с вызовом переменных:
Такие теги, которые включают какие-то локальные файлы, назвали локальными сущностями. А затем, возник логичный вопрос – а что если подключать в документ не только локальные файлы, а скажем, получать ответы от каких-то внешних ресурсов в том же формате и подключать их в документ. Например, получить текущую дату со стороннего сайта, который возвращает в ответе XML-код, содержащий текущую дату. И так появились уже внешние сущности – подключение в документ структур со сторонних ресурсов.
В коде они выглядят точно так же как локальные сущности, с той поправкой, что путь у них указывает не на локальный файл, а на внешний ресурс:
Как вы уже поняли - язык XML используется для хранения и передачи структурированных данных. Этот формат хранения удобен своей универсальностью – работать с XML документами можно практически в любой системе, вне зависимости от стека технологий и вектора разработки. То есть, работа с XML возможна из коробки в каждом языке программирования, вне зависимости от того, десктопное ли приложение разрабатывается, или веб. Именно благодаря своей универсальности, XML используется именно в том месте, которое нас и интересует с точки зрения веб-безопасности – в веб api. О том, что это и как работает – далее:
API
API (Application programming interface) – это программный интерфейс, при помощи которого происходит взаимодействие между разными информационными структурами. Интерфейс этот предоставляет сторонней структуре определенные функции. Как правило это происходит так же как с функциями в программировании – входные данные, их обработка внутри функции, и выходные данные как результат. API сейчас используются везде, далеко не только в вебе, например, для связи между собой десктопного приложения с какими-либо сторонними сервисами, для облегчения работы сторонним разработчикам над открытыми проектами и т.д.
Приведу простой пример – если разработчику требуется добавить на свой сайт карту с указанием конкретного места или даже нескольких конкретных мест – ему не обязательно разрбатывать собственную карту. Он может добавить себе на сайт карту одного из крупных сервисов, с указанием на ней всех нужных элементов, например карту от гугла или яндекса.
Добавление такой сторонней карты себе на сайт – наглядный пример работы API. Разработчики гугла добавляют к своему детищу интерфейс, при помощи кторого любой желающий может добавить такую карту себе на сайт. Такой интерфейс предоставляет определенные функции, которые может использовать тот, кто будет добавлять карту – указание одного или нескольких конкретных мест, настройка масштаба и т.д. Все это реализуется через API.
Но API может использоваться не только для обращения к сторонним сервисам. Так же, API может быть использован для “общения” структур в рамках одного приложения, например, для передачи данных между бэкендом и фронтендом. То есть, API по сути является прослойкой, которая служит для разделения бизнес логики и представления, что позволяет сделать, насколько это возможно, независимой работу фронтендеров и бэкендеров, тем самым облегчая жизнь разработчикам на протяжении всей разработки и дальнейшей поддержки приложения.
API в обоих этих случаях служит неким “переводчиком” - получает на вход какие-то данные с одной из сторон, обрабатывает их в удобный формат для другой стороны, а затем возвращает результат, удобный для первой стороны.
Но на каком общем языке общаются между собой через api структуры. Сейчас в основном везде используется json, но остались виды api, в которых единственным способом передачи данных является XML. И вот здесь мы и подходим к тому, как XML используется в веб-приложениях. И если структуры общаются между собой при помощи XML, а нам удасться его как-то задействовать в своих целях – это может быть очень опасно для целевого веб-приложения. Но обо всем по порядку.
Так же, XML может использоваться не только в api запросах, но и просто передаваться в запросах к серверу, для дальнейшей обработки данных на бэкенде. Такое встречается гораздо реже, как правило в каких-то самописных решениях, но все же встречается.
В целом, это вся теоритическая база, которую нужно понимать для того, чтобы двигаться дальше. Поэтому, далее мы уже переходим к непосредственно XML-инъекциям:
XML-инъекции. Теория и практика
Теперь же, поговорим про XML-иньекции и как они собственно работают. И когда речь идет о XML-инъекциях, как правило, подразумевается такая атака как XXE – XML eXternal Entities injection, т.е. иньекция внешних XML сущностей. Самая большая проблема безопасности XML кроется именно во внешних сущностях.
Теперь, когда мы примерно понимаем что такое XML и как и где он используется в веб-приложениях, можно переходить уже непосредственно к поиску уязвимостей на конкретном сайте. Мест, где можно встретить XML-инъекции в приложении может быть много, поэтому разберем по порядку где именно искать такие места и как эксплуатировать.
XXE непосредственно в запросах
Как уже было упомянуто выше – в API запросах, либо просто в запросах к серверу, может передаваться XML-код. От одной структуры к другой. По сути, это стандартные http-запросы, в теле которых содержится xml-код, содержащий какую-либо информацию. Чтобы не зацикливаться на теории, предлагаю сразу отправиться “на полигон”. В качестве тестового приложения, уязвимого к XXE будем использовать bee-waap. Это веб-приложение, которое содержит большое количество уязвимых скриптов, под самые разные уязвимости, и служит как раз для отработки навыков.
(Скачать уязвимую виртуальную машину можно тут: https://www.vulnhub.com/entry/bwapp-bee-box-v16,53/ )
Переходим в приложение, логинимся под дефолтными данными (bee/bug) и видим список всех доступных уязвимостей на выбор:
Нас интересует “XML External Entity Attacks (XXE)” в разделе “/ A7 - Missing Functional Level Access Control /”
Вот так выглядит сама уязвимая страница:
На первый взгляд непонятно куда смотреть и по нажатию на кнопку ничего не происходит. И вот здесь нам понадобится инструмент для просмотра заголовков запросов и ответов. Для этого можно использовать либо встроенные в браузер средства, что не очень удобно, либо, что более предпочтительно задействовать специальные сторонние инструменты по типу ZAProxy или Burp Suite. Я буду использовать последний.
Итак, открываем страницу. По простому обновлению страницы ничего интересного не происходит, а вот при нажатии на кнопку, мы уже ловим следующий запрос:
Что мы видим ? В теле запроса передается XML-код в чистом виде. Проведя простые манипуляции с подменой содержимого тегов, выясняем опытным путем, что содержимое тега “<login>” в запросе возвращается в ответе:
Для нас это очень хорошо, так как именно это обеспечит нам не слепую иньекцию. Далее вы в этом убедитесь.
Что мы можем с этим сделать ? Мы видим перед собой не полную структуру документа, а лишь некоторые теги. Однако, посмотрев на структуру, мы можем предположить что тег <reset> является корневым. А значит, можно попробовать провести иньекцию, несмотря на то, что на первый взгляд нам не доступна область подключения. Давайте попробуем:
Для начала вспомним как работают внешние сущности – они подключают в документ какой-либо ответ со стороннего ресурса, либо локальные файлы. А значит, мы можем попробовать изменить документ таким образом, чтобы он включил в состав ответа какой-либо файл на сервере.
Для начала попробуем самую классику - /etc/passwd. Но почему если файл локальный, мы используем в иньекции именно внешнюю сущность для подключения файла ? Дело в том, что локалльные сущности не подключат файлы, для этого мы воспользуемся протоколом file://, который работает как url и позволит нам через внешнюю сущность обращаться к локальным файлам на сервере.
Для получения ответа будем использовать тег login, т.к. именно его содержимое возвращается в ответе.
Теперь попробуем внедрить сущность. Добавляем в содержимое XML-запроса следующую строку:
Если разобраться, она означает следующее – мы создаем внешнюю сущность с именем “test” и используем file:// протокол для обращения к файлу /etc/passwd, который в linux-системах содержит достаточно чувствительную информацию о пользователях ОС.
Это абсолютно классический payload для XML-иньекций. Но создать саму сущность мало, ее еще надо включить в документ.
Для этого добавляем вот такое содержимое в тег <login>:
Таким образом мы включаем в документ эдакую переменную, которую и создали. В итоге получим вот такое тело запроса:
И вот что мы увидим после отправки запроса:
А видим мы соержимое файла /etc/paswd, содержимое которого является одним из самых чувствительных данных в системе.
Пример максимально классический, на практике скорее всего все будет по другому, но суть остается той же – если есть возможность контролировать содержимое документа, он потенциально подвержен XXE injection.
Но, здесь нельзя не упомянуть, что для реализации такой атаки, вам должно очень сильно повезти. Во первых, такая атака не должна быть слепой, т.е. в ответе веб-сервера должен вернуться XML документ с внедренной сущностью, что уже само по себе не особо частое явление. Конкретно здесь нам повезло с тегом login, однако такое вообще не обязательно должно происходить.
Во вторых – все очень сильно зависит от стека и настроек веб-сервера и технологий. Например, протокол SOAP четко отписывает в требованиях запрет на использование внешних сущностей. Так же, должна быть возможность задействовать протокол file://
Ну и в третьих – мы могли контролировать “шапку” документа – ту часть что находится над корневым тегом и в которой мы обьявляли сущность. Если бы мы не могли достучаться за пределы корневого тега “<reset>”, то это вызвало бы проблемы. Правда в таком случае была бы возможна другая атака, связаная с XML, но об этом позже.
Есть очень много мелких моментов и ошибок, которые должен допустить разработчик, чтобы данная атака сработала.
Так что, такой кейс будет реален, скорее всего если только разработчики реализовали какое-то собственное решение, основаное на XML. В других же случаях, встретить что-то подобное сейчас будет большой редкостью.
Дополнительные возможности XXE
Так же, XXE можно использовать не только для включения локальных файлов (LFI). Иньекции внешних сущностей можно использовать и для других атак. Давайте посмотрим какие еще возможности открывает для нас XXE:
Важная оговорка – все эти возможности открываются при определенных условиях или ошибках разработчика.
SSRF
Один из самых логичных векторов раскрутки. XXE почти всегда поволяет провести атаки типа SSRF. Для тех, кто не в курсе – это атака, которая позволяет отправлять запросы извне в локальную сеть, используя для этого узявимый сервер как некий “мост” между глобальной и локальной сетями.
Реализация атаки так же проводится через внедрение сущностей. Помните, в теоретической части статьи, я говорил что внешние сущности позволяют получать информацию со сторонних сервисов. Именно благодаря этой возможности мы можем попробовать обратиться в локальную сеть через сущности. Внедряем в документ следующую внешнюю сущность:
Как итог сервер попытается постучаться во внутреннюю сеть на адрес 192.168.1.5
К чему это может привести и чем это опасно можно более подробно почитать здесь
А если вкратце, то здесь тоже, если сложаться звезды и мы будем видеть ошибки, как в примере, мы сможем:
1. Обнаружить живые хосты в локальной сети:
2. Проверить порты на этих хостах:
3. Взаимодействовать с некоторыми файлами по некоторым из протоколов:
RCE
Самый выгодный способ с точки зрения атакующего, но очень маловероятный. Для того чтобы он сработал, должен быть установлен модуль expect в php. Это обертка, которую атакующий может использовать для выполнения комманд на сервере.
Таким образом, мы можем использовать следующую сущность:
Для выполнения комманды id. Как итог – в ответе получим результат выполнения комманды id.
К чему это может привести, думаю описывать не надо – если мы можем выполнять комманды на сервере, то нам открываются практически бесконечные возможности. Но еще раз повторюсь – вероятность найти такое крайне мала.
DOS
При помощи xml-иньекции можно на какое-то время вывести сайт из строя. Для этого внедряется вот такая сущность:
Работает это однако тоже далеко не всегда.
Получение доступа к исходному коду страницы
Логично, что если мы можем читать файлы на сервере, то мы можем получить и доступ к исходному коду самого веб-приложения. Профит от таких действий ности исключительно информативный характер, но ценность такой информации сложно переоценить, ведь это поможет перейти от тестирования из черной коробки в белую.
Такой вектор раскручивается следующим образом:
Включить сам файл с кодом php так, как мы это делали с /etc/passwd скорее всего не получится. Поэтому, для тих целей будем использовать php-обертку, для того, чтобы закодировать ответ в base64. Пэйлоад в этом случае будет выглядеть вот так:
(Этот же способ может работать и для включения обычных файлов, в том случае, если в ответе от сервера возникают какие-то проблемы со структурой xml)
В результате отправки вредоносного запроса мы получим строку, закодированную в base64:
Если мы раскодируем ее (сделать это можно любым онлайн декодером), то увидим, что внутри содержится код файла index.php:
Xinclude
Помните, чуть выше, когда мы рассматривали пример, я говорил что нам повезло, что мы можем обращаться к шапке документа, так как иначе осуществить XXE атаку было бы невозможно ? Так вот, в некоторых случаях, даже если создание и внедрение сущностей невозможно, имеет место быть такая атака как “xinclude”
Что это вообще такое ? Давайте разбираться:
Для классических атак XXE мы использовали сущности, которые создавали согласно стандарту DTD в шапке документа, а потом вызывали их в документе.
Но, если в запросе передается только часть xml-документа, и содержимое потом попадает в состав других тегов. В этмо случае мы не можем стучаться в область, в которой происходит создание сущностей. Но тут имеет место быть другая атака, уже без использования сущностей, но с использованием пространства имен Xinclude.
Xinclude – это механизм, который служит для включения в XML-файлы частей других xml-файлов или даже текстовых файлов. В целом, описание по функционалу похоже на сущности, но работает все несколько иначе. Не будем углубляться в это с позиции разработчика, нам важно знать, чем эта технология может быть полезна нам. А полезна она тем же, что и с сущности, так как при ее помощи мы можем делать практически то же самое.
Скажем, если попробовать так же получить доступ к содержимому файла /etc/passwd, но уже при помощи xinclude – сделать это можно следующим образом:
Создаем вот такие теги:
Здесь мы подключаем пространство имен xinclude, а затем подключаем локальный файл в состав документа по тому же протоколу file://
И в результате мы получим ту же самую картину, что и при иньекции внешних сущностей:
XXE при парсинге документов
Так же, в рамках статьи хотелось бы упомянуть достаточно интересный кейс, про иньекции через документы.
Нередко бывает, что сайты позволяют загружать файлы определенного формата, например docx, pdf, obt и т.д. О чем в первую очередь думает атакующий, когда видит такую форму ? Конечно же об уязвимости загрузки файлов и реализует именно этот вектор, пытаясь залить какой-то шелл. И казалось бы, при чем тут XML-иньекции. Но, как раз таки при чем. Потому что файлы форматов DOCX, ODT – все эти форматы основаны на XML ! По сути, каждый из этих форматов всего лишь архив, которые содержит n-ое количество XML файлов, содержащих текст документов, а так же релизующих отступы и стили текста при помощи XML тегов и атрибутов к ним.
В этом можно убедиться, если взять любой docx файл и открыть его как архив.
В linux это можно сделать простой консольной командой unzip, входящей в состав пакета zip:
Как видим – все так и есть, формат docx всеголишь архив с xml-файлами. А значит, если сервер подгружает себе такие файлы, для их дальнейшей обработки, скорее всего он работает с ними на уровне XML документов в архиве, а значит, теоретически, такая функция сайта может привести к XML-иньекции.
Разберем чуть более подробно, как это может случиться. Как пример, возьмем реально существующую уязвимость, которая была найдена в открытом ПО OpenCats. Эта программа служит для упрощения работы рекрутеров, помогая упростить и автоматизировать процесс подбора персонала, рпеализуя такие функции как сбор и отправка резюме, создание вакансий и т.д.
Уязвимость получила номер CVE-2019-13358 и является отличным классическим примером XML-иньекции через документы формата DOCX.
Именно в функции подачи резюме и была обнаружена интересующая нас уязвимость. Как известно, большинство людей составляют резюме в форматах docx для дальнейшей отправки их по почте и прикрепления в других местах. Но площадки нередко используют другой способ представления, и, чтобы облегчить работу пользователю, добавляют функцию импорта данных резюме из документа.
Примерно так получилось и здесь:
Была добавлена функция импорта резюме. Но, код был написан некорректно, что и привело к уязвимости.
Первое, что нам нужно сделать – создать простой docx документ. Надеюсь, как это сделать, обьяснять не надо. Далее я добавлю в этот документ одну единственную запись – строку “Hello world”. Далее сохраням документ и импортируем его в поле для резюме:
Как видим, после импорта документа, его содержимое автоматически импортируется в поле.
Идем дальше. Как я уже сказал – формат docx, это просто архив, включающий в себя различные упакованные xml-файлы. В этих файлах содержится разная информация, например метаданные, стили, шрифты и т.д. А весь основной контент документа содержится в файле document.xml
Именно его мы и будем использовать для атаки.
Для начала распакуем тот же документ “Hello world” стандартной утиллитой unzip. Лучше распаковать все файлы в отдельную директорию, для дальнейшего удобства, чтобы избежать путаницы в дальнейшем:
Затем, откроем файл word/document.xml любым редактором. Подойдет как IDE, так и любой текстовый редактор:
Ну а дальше уже по классической схеме – сначала добавляем саму сущность в шапку:
А затем вызываем ее в документе, в месте, которое отображалось в импорте. В моем случае, единственная строка – hello world, а значит я просто найду тег с ней в документе и заменю на сущность:
После этого сохраняем и закрываем файл. Далее архив нужно упаковать обратно. По сути, для тестов будет достаточно упаковать туда один только document.xml файл, самой функциональности документа это не навредит.
Сделать это можно так же, при помощи дефолтной команды zip:
Получаем готовый docx документ. Далее пытемся импортировать его как резюме, и:
Получаем содержимое файла etc/passwd на сервере.
Кратко, подведем итог почему так произошло:
Функция импорта из документа работала с форматом docx, просто распаковывая его и работая уже с содержимым xml-файлов. Но разработчики не учли, что в этих xml-файлах может содержаться вредносный код. Это и привело к XML-иньекции. (После обнаружения, уязвимость, разумеется, была пропатчена)
Итог:
Итак, мы разобрали XML-иньекции. Какой вывод можно сделать ? XML-иньекции – сейчас достаточно редки. Вероятность встретить классические кейсы крайне мала. Для того, чтобы найти что-то подобное на целелвом сайте атакующему должно очень сильно повезти. Слишком много звезд должно сойтись, чтобы уязвимость можно было нормально раскрутить до какого-то ощутимого профита. Там и иньекция должна быть не слепой, и ошибки разработчик должен допустить достаточно глупые. Поэтому уязвимость, по моему скромному мнению, хоть и заслуживает внимания, все же на практике как правило себя не оправдывает и встречается довольно редко. Так что, знать об уязвимости стоит, но врятли вы ее часто будете встречать на деле. Однако, знания, как известно, лишними не бывают, и лучше знать, но не наткнуться, чем наткнуться и не знать. Кто знает, может однажды, именно такая уязвимость как XML-иньекция станет ключом к нужному вам серверу.
На этом, с темой XML-иньекций у меня все, всем добра !
© Urob0ros, специально для форума xss.pro
Всех приветствую ! Сегодня, как и обещал в прошлой статье, поговорим об XML-инъекциях. Уязвимость достаточно сложная и требует неплохой теоретической базы. Поэтому я постараюсь рассказать те теоретические аспекты, которые необходимы для общего понимания, при этом не углубляясь в вещи, которые особо не нужны. Но если кто захочет более подробно разобраться в теме – по ходу статьи буду оставлять небольшие “подсказки” куда копать и куда смотреть ) Ну и естественно разберем как уязвимость искать, эксплуатировать, какой профит с нее можно поиметь, как автоматизировать некоторые процессы и т.д. А посмотреть там есть на что – это и локальное включение файлов, и Server Side Request Forgery, а если повезет, то и может RCE. Ну и несколько видов самих иньекций. Сразу предупреждаю – статья получилась достаточно обьемной, поэтому запасайтесь попкорном ) Поехали:
Теория – XML и API
Для более полного понимаю что такое XML-иньекции, нужно ознакомиться с двумя понятиями – что такое сам XML и как он связан с такой штукой как API. Это нужно для понимания того, как и где вообще веб-приложения связаны и работают с XML. Именно это я сейчас и постараюсь обьяснить:
XML
XML – с английского эта аббривиатура расшифровывается как eXtensible Markup Language, то есть расширяемый язык разметки. Есть большое количество языков, основаных именно на XML – например, XAML, который используется в WPF в .NET, и множество других языков для самых разных сфер деятельности – медицины, бухгалтерии и т.д. Даже векторный формат изображений SVG основан на XML и является языком разметки масштабируемой графики. Вообщем, XML – это золотой стандарт для языков разметки, который является прародителем многих современных языков.
Если вы знакомы с HTML, то примерно представляете как выглядит этот язык разметки. Но все же есть некоторые различия. Во первых, HTML используется для представления и отображения данных, а XML, в первую очередь, для их передачи. Да и появился html раньше.
Но во многом эти язки разметки похожи. Так же как html этот язык состоит из тегов и атрибутов к ним. Стандартная структура XML документа выглядит примерно вот так:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<cars>
<model generation="1.0" >test1</model>
<model generation="2.0" >test2</model>
</cars>
Первой строкой идет заголовок, в котором сообщается версия XML и кодировка
Далее следует так называемый “основной тег” или корень – главный тег, внутри которого находятся все остальные. Проводя аналогию с тем же html – там есть тег <html>, который являтся корневым. Здесь примерно то же самое, с тем отличием, что название тега определяет сам создатель – он зависит от того, какие данные будут хранится в документе.
В примере это тег - <cars>, который говорит о том, что в документе будет содержаться информация об автомобилях.
Ну и далее идет непосредственно содержимое документа в виде тегов и атрибутов – в примере это марка автомобиля и модель.
Вся эта структура вполне себе понятна и логична, особенно если вы знакомы с html.
Вторая важная деталь в XML, о которой нужно знать – внешние сущности (External entities). Что это вообще такое ?
Начнем сначала:
В документах XML может содержаться разная информация и ее нужно каким-то образом стандартизировать. Это нужно для удобства дальнейшей работы с документами. Как правило, для такой локальной стандартизации в документ подключается другой документ, который и содержит информацию о том, как XML-документ должен выглядеть. Для этого, используются два подхода: XSD (XML Schema Definition) и DTD (Document Type Definition) Нас здесь будет интересовать конктретно второй тип, поэтому остановимся на DTD.
Для такой стандартизации используется сторонний документ формата .dtd, который и содержит информацию о том, какие теги и какие значения должны содержаться в документе. Сам файл типа .dtd нас не особо интересует, куда более интересно как такие файлы связываются с документами, которые они стандартизируют.
А связываются они так:
Создается тег Document Type Declaration, который выглядит следующим образом:
XML:
<!DOCTYPE valid SYSTEM "valid.dtd">
Но это не самое интересное. Дело в том, что в формате DTD есть еще такая вещь, как сущности. Сущности нужны в первую очередь для того, чтобы подключать в документ часто используемые фрагменты XML. Достаточно удобно, чтобы не переписывать одно и то же, можно просто добавить строку следующего вида:
XML:
<!ENTITY name 'path'>
XML:
<tag>&name;<tag>
Такие теги, которые включают какие-то локальные файлы, назвали локальными сущностями. А затем, возник логичный вопрос – а что если подключать в документ не только локальные файлы, а скажем, получать ответы от каких-то внешних ресурсов в том же формате и подключать их в документ. Например, получить текущую дату со стороннего сайта, который возвращает в ответе XML-код, содержащий текущую дату. И так появились уже внешние сущности – подключение в документ структур со сторонних ресурсов.
В коде они выглядят точно так же как локальные сущности, с той поправкой, что путь у них указывает не на локальный файл, а на внешний ресурс:
XML:
<!ENTITY test SYSTEM 'http://example.com'>
Как вы уже поняли - язык XML используется для хранения и передачи структурированных данных. Этот формат хранения удобен своей универсальностью – работать с XML документами можно практически в любой системе, вне зависимости от стека технологий и вектора разработки. То есть, работа с XML возможна из коробки в каждом языке программирования, вне зависимости от того, десктопное ли приложение разрабатывается, или веб. Именно благодаря своей универсальности, XML используется именно в том месте, которое нас и интересует с точки зрения веб-безопасности – в веб api. О том, что это и как работает – далее:
API
API (Application programming interface) – это программный интерфейс, при помощи которого происходит взаимодействие между разными информационными структурами. Интерфейс этот предоставляет сторонней структуре определенные функции. Как правило это происходит так же как с функциями в программировании – входные данные, их обработка внутри функции, и выходные данные как результат. API сейчас используются везде, далеко не только в вебе, например, для связи между собой десктопного приложения с какими-либо сторонними сервисами, для облегчения работы сторонним разработчикам над открытыми проектами и т.д.
Приведу простой пример – если разработчику требуется добавить на свой сайт карту с указанием конкретного места или даже нескольких конкретных мест – ему не обязательно разрбатывать собственную карту. Он может добавить себе на сайт карту одного из крупных сервисов, с указанием на ней всех нужных элементов, например карту от гугла или яндекса.
Добавление такой сторонней карты себе на сайт – наглядный пример работы API. Разработчики гугла добавляют к своему детищу интерфейс, при помощи кторого любой желающий может добавить такую карту себе на сайт. Такой интерфейс предоставляет определенные функции, которые может использовать тот, кто будет добавлять карту – указание одного или нескольких конкретных мест, настройка масштаба и т.д. Все это реализуется через API.
Но API может использоваться не только для обращения к сторонним сервисам. Так же, API может быть использован для “общения” структур в рамках одного приложения, например, для передачи данных между бэкендом и фронтендом. То есть, API по сути является прослойкой, которая служит для разделения бизнес логики и представления, что позволяет сделать, насколько это возможно, независимой работу фронтендеров и бэкендеров, тем самым облегчая жизнь разработчикам на протяжении всей разработки и дальнейшей поддержки приложения.
API в обоих этих случаях служит неким “переводчиком” - получает на вход какие-то данные с одной из сторон, обрабатывает их в удобный формат для другой стороны, а затем возвращает результат, удобный для первой стороны.
Но на каком общем языке общаются между собой через api структуры. Сейчас в основном везде используется json, но остались виды api, в которых единственным способом передачи данных является XML. И вот здесь мы и подходим к тому, как XML используется в веб-приложениях. И если структуры общаются между собой при помощи XML, а нам удасться его как-то задействовать в своих целях – это может быть очень опасно для целевого веб-приложения. Но обо всем по порядку.
Так же, XML может использоваться не только в api запросах, но и просто передаваться в запросах к серверу, для дальнейшей обработки данных на бэкенде. Такое встречается гораздо реже, как правило в каких-то самописных решениях, но все же встречается.
В целом, это вся теоритическая база, которую нужно понимать для того, чтобы двигаться дальше. Поэтому, далее мы уже переходим к непосредственно XML-инъекциям:
XML-инъекции. Теория и практика
Теперь же, поговорим про XML-иньекции и как они собственно работают. И когда речь идет о XML-инъекциях, как правило, подразумевается такая атака как XXE – XML eXternal Entities injection, т.е. иньекция внешних XML сущностей. Самая большая проблема безопасности XML кроется именно во внешних сущностях.
Теперь, когда мы примерно понимаем что такое XML и как и где он используется в веб-приложениях, можно переходить уже непосредственно к поиску уязвимостей на конкретном сайте. Мест, где можно встретить XML-инъекции в приложении может быть много, поэтому разберем по порядку где именно искать такие места и как эксплуатировать.
XXE непосредственно в запросах
Как уже было упомянуто выше – в API запросах, либо просто в запросах к серверу, может передаваться XML-код. От одной структуры к другой. По сути, это стандартные http-запросы, в теле которых содержится xml-код, содержащий какую-либо информацию. Чтобы не зацикливаться на теории, предлагаю сразу отправиться “на полигон”. В качестве тестового приложения, уязвимого к XXE будем использовать bee-waap. Это веб-приложение, которое содержит большое количество уязвимых скриптов, под самые разные уязвимости, и служит как раз для отработки навыков.
(Скачать уязвимую виртуальную машину можно тут: https://www.vulnhub.com/entry/bwapp-bee-box-v16,53/ )
Переходим в приложение, логинимся под дефолтными данными (bee/bug) и видим список всех доступных уязвимостей на выбор:
Нас интересует “XML External Entity Attacks (XXE)” в разделе “/ A7 - Missing Functional Level Access Control /”
Вот так выглядит сама уязвимая страница:
На первый взгляд непонятно куда смотреть и по нажатию на кнопку ничего не происходит. И вот здесь нам понадобится инструмент для просмотра заголовков запросов и ответов. Для этого можно использовать либо встроенные в браузер средства, что не очень удобно, либо, что более предпочтительно задействовать специальные сторонние инструменты по типу ZAProxy или Burp Suite. Я буду использовать последний.
Итак, открываем страницу. По простому обновлению страницы ничего интересного не происходит, а вот при нажатии на кнопку, мы уже ловим следующий запрос:
Что мы видим ? В теле запроса передается XML-код в чистом виде. Проведя простые манипуляции с подменой содержимого тегов, выясняем опытным путем, что содержимое тега “<login>” в запросе возвращается в ответе:
Для нас это очень хорошо, так как именно это обеспечит нам не слепую иньекцию. Далее вы в этом убедитесь.
Что мы можем с этим сделать ? Мы видим перед собой не полную структуру документа, а лишь некоторые теги. Однако, посмотрев на структуру, мы можем предположить что тег <reset> является корневым. А значит, можно попробовать провести иньекцию, несмотря на то, что на первый взгляд нам не доступна область подключения. Давайте попробуем:
Для начала вспомним как работают внешние сущности – они подключают в документ какой-либо ответ со стороннего ресурса, либо локальные файлы. А значит, мы можем попробовать изменить документ таким образом, чтобы он включил в состав ответа какой-либо файл на сервере.
Для начала попробуем самую классику - /etc/passwd. Но почему если файл локальный, мы используем в иньекции именно внешнюю сущность для подключения файла ? Дело в том, что локалльные сущности не подключат файлы, для этого мы воспользуемся протоколом file://, который работает как url и позволит нам через внешнюю сущность обращаться к локальным файлам на сервере.
Для получения ответа будем использовать тег login, т.к. именно его содержимое возвращается в ответе.
Теперь попробуем внедрить сущность. Добавляем в содержимое XML-запроса следующую строку:
<!DOCTYPE test [<!ENTITY test SYSTEM 'file:///etc/passwd'>]>Если разобраться, она означает следующее – мы создаем внешнюю сущность с именем “test” и используем file:// протокол для обращения к файлу /etc/passwd, который в linux-системах содержит достаточно чувствительную информацию о пользователях ОС.
Это абсолютно классический payload для XML-иньекций. Но создать саму сущность мало, ее еще надо включить в документ.
Для этого добавляем вот такое содержимое в тег <login>:
&test;Таким образом мы включаем в документ эдакую переменную, которую и создали. В итоге получим вот такое тело запроса:
И вот что мы увидим после отправки запроса:
А видим мы соержимое файла /etc/paswd, содержимое которого является одним из самых чувствительных данных в системе.
Пример максимально классический, на практике скорее всего все будет по другому, но суть остается той же – если есть возможность контролировать содержимое документа, он потенциально подвержен XXE injection.
Но, здесь нельзя не упомянуть, что для реализации такой атаки, вам должно очень сильно повезти. Во первых, такая атака не должна быть слепой, т.е. в ответе веб-сервера должен вернуться XML документ с внедренной сущностью, что уже само по себе не особо частое явление. Конкретно здесь нам повезло с тегом login, однако такое вообще не обязательно должно происходить.
Во вторых – все очень сильно зависит от стека и настроек веб-сервера и технологий. Например, протокол SOAP четко отписывает в требованиях запрет на использование внешних сущностей. Так же, должна быть возможность задействовать протокол file://
Ну и в третьих – мы могли контролировать “шапку” документа – ту часть что находится над корневым тегом и в которой мы обьявляли сущность. Если бы мы не могли достучаться за пределы корневого тега “<reset>”, то это вызвало бы проблемы. Правда в таком случае была бы возможна другая атака, связаная с XML, но об этом позже.
Есть очень много мелких моментов и ошибок, которые должен допустить разработчик, чтобы данная атака сработала.
Так что, такой кейс будет реален, скорее всего если только разработчики реализовали какое-то собственное решение, основаное на XML. В других же случаях, встретить что-то подобное сейчас будет большой редкостью.
Дополнительные возможности XXE
Так же, XXE можно использовать не только для включения локальных файлов (LFI). Иньекции внешних сущностей можно использовать и для других атак. Давайте посмотрим какие еще возможности открывает для нас XXE:
Важная оговорка – все эти возможности открываются при определенных условиях или ошибках разработчика.
SSRF
Один из самых логичных векторов раскрутки. XXE почти всегда поволяет провести атаки типа SSRF. Для тех, кто не в курсе – это атака, которая позволяет отправлять запросы извне в локальную сеть, используя для этого узявимый сервер как некий “мост” между глобальной и локальной сетями.
Реализация атаки так же проводится через внедрение сущностей. Помните, в теоретической части статьи, я говорил что внешние сущности позволяют получать информацию со сторонних сервисов. Именно благодаря этой возможности мы можем попробовать обратиться в локальную сеть через сущности. Внедряем в документ следующую внешнюю сущность:
<!DOCTYPE test [<!ENTITY test SYSTEM '[URL='http://192.168.1.5/']http://192.168.1.5[/URL]>]>Как итог сервер попытается постучаться во внутреннюю сеть на адрес 192.168.1.5
К чему это может привести и чем это опасно можно более подробно почитать здесь
А если вкратце, то здесь тоже, если сложаться звезды и мы будем видеть ошибки, как в примере, мы сможем:
1. Обнаружить живые хосты в локальной сети:
2. Проверить порты на этих хостах:
3. Взаимодействовать с некоторыми файлами по некоторым из протоколов:
RCE
Самый выгодный способ с точки зрения атакующего, но очень маловероятный. Для того чтобы он сработал, должен быть установлен модуль expect в php. Это обертка, которую атакующий может использовать для выполнения комманд на сервере.
Таким образом, мы можем использовать следующую сущность:
<!DOCTYPE test [<!ENTITY test SYSTEM 'expect://id'>]>Для выполнения комманды id. Как итог – в ответе получим результат выполнения комманды id.
К чему это может привести, думаю описывать не надо – если мы можем выполнять комманды на сервере, то нам открываются практически бесконечные возможности. Но еще раз повторюсь – вероятность найти такое крайне мала.
DOS
При помощи xml-иньекции можно на какое-то время вывести сайт из строя. Для этого внедряется вот такая сущность:
<!ENTITY dos SYSTEM "/dev/zero">Работает это однако тоже далеко не всегда.
Получение доступа к исходному коду страницы
Логично, что если мы можем читать файлы на сервере, то мы можем получить и доступ к исходному коду самого веб-приложения. Профит от таких действий ности исключительно информативный характер, но ценность такой информации сложно переоценить, ведь это поможет перейти от тестирования из черной коробки в белую.
Такой вектор раскручивается следующим образом:
Включить сам файл с кодом php так, как мы это делали с /etc/passwd скорее всего не получится. Поэтому, для тих целей будем использовать php-обертку, для того, чтобы закодировать ответ в base64. Пэйлоад в этом случае будет выглядеть вот так:
<!DOCTYPE test [<!ENTITY test SYSTEM 'php://filter/convert.base64-encode/resource=index.php'>]>(Этот же способ может работать и для включения обычных файлов, в том случае, если в ответе от сервера возникают какие-то проблемы со структурой xml)
В результате отправки вредоносного запроса мы получим строку, закодированную в base64:
Если мы раскодируем ее (сделать это можно любым онлайн декодером), то увидим, что внутри содержится код файла index.php:
Xinclude
Помните, чуть выше, когда мы рассматривали пример, я говорил что нам повезло, что мы можем обращаться к шапке документа, так как иначе осуществить XXE атаку было бы невозможно ? Так вот, в некоторых случаях, даже если создание и внедрение сущностей невозможно, имеет место быть такая атака как “xinclude”
Что это вообще такое ? Давайте разбираться:
Для классических атак XXE мы использовали сущности, которые создавали согласно стандарту DTD в шапке документа, а потом вызывали их в документе.
Но, если в запросе передается только часть xml-документа, и содержимое потом попадает в состав других тегов. В этмо случае мы не можем стучаться в область, в которой происходит создание сущностей. Но тут имеет место быть другая атака, уже без использования сущностей, но с использованием пространства имен Xinclude.
Xinclude – это механизм, который служит для включения в XML-файлы частей других xml-файлов или даже текстовых файлов. В целом, описание по функционалу похоже на сущности, но работает все несколько иначе. Не будем углубляться в это с позиции разработчика, нам важно знать, чем эта технология может быть полезна нам. А полезна она тем же, что и с сущности, так как при ее помощи мы можем делать практически то же самое.
Скажем, если попробовать так же получить доступ к содержимому файла /etc/passwd, но уже при помощи xinclude – сделать это можно следующим образом:
Создаем вот такие теги:
XML:
<test xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/>
</test>
И в результате мы получим ту же самую картину, что и при иньекции внешних сущностей:
XXE при парсинге документов
Так же, в рамках статьи хотелось бы упомянуть достаточно интересный кейс, про иньекции через документы.
Нередко бывает, что сайты позволяют загружать файлы определенного формата, например docx, pdf, obt и т.д. О чем в первую очередь думает атакующий, когда видит такую форму ? Конечно же об уязвимости загрузки файлов и реализует именно этот вектор, пытаясь залить какой-то шелл. И казалось бы, при чем тут XML-иньекции. Но, как раз таки при чем. Потому что файлы форматов DOCX, ODT – все эти форматы основаны на XML ! По сути, каждый из этих форматов всего лишь архив, которые содержит n-ое количество XML файлов, содержащих текст документов, а так же релизующих отступы и стили текста при помощи XML тегов и атрибутов к ним.
В этом можно убедиться, если взять любой docx файл и открыть его как архив.
В linux это можно сделать простой консольной командой unzip, входящей в состав пакета zip:
Как видим – все так и есть, формат docx всеголишь архив с xml-файлами. А значит, если сервер подгружает себе такие файлы, для их дальнейшей обработки, скорее всего он работает с ними на уровне XML документов в архиве, а значит, теоретически, такая функция сайта может привести к XML-иньекции.
Разберем чуть более подробно, как это может случиться. Как пример, возьмем реально существующую уязвимость, которая была найдена в открытом ПО OpenCats. Эта программа служит для упрощения работы рекрутеров, помогая упростить и автоматизировать процесс подбора персонала, рпеализуя такие функции как сбор и отправка резюме, создание вакансий и т.д.
Уязвимость получила номер CVE-2019-13358 и является отличным классическим примером XML-иньекции через документы формата DOCX.
Именно в функции подачи резюме и была обнаружена интересующая нас уязвимость. Как известно, большинство людей составляют резюме в форматах docx для дальнейшей отправки их по почте и прикрепления в других местах. Но площадки нередко используют другой способ представления, и, чтобы облегчить работу пользователю, добавляют функцию импорта данных резюме из документа.
Примерно так получилось и здесь:
Была добавлена функция импорта резюме. Но, код был написан некорректно, что и привело к уязвимости.
Первое, что нам нужно сделать – создать простой docx документ. Надеюсь, как это сделать, обьяснять не надо. Далее я добавлю в этот документ одну единственную запись – строку “Hello world”. Далее сохраням документ и импортируем его в поле для резюме:
Как видим, после импорта документа, его содержимое автоматически импортируется в поле.
Идем дальше. Как я уже сказал – формат docx, это просто архив, включающий в себя различные упакованные xml-файлы. В этих файлах содержится разная информация, например метаданные, стили, шрифты и т.д. А весь основной контент документа содержится в файле document.xml
Именно его мы и будем использовать для атаки.
Для начала распакуем тот же документ “Hello world” стандартной утиллитой unzip. Лучше распаковать все файлы в отдельную директорию, для дальнейшего удобства, чтобы избежать путаницы в дальнейшем:
Затем, откроем файл word/document.xml любым редактором. Подойдет как IDE, так и любой текстовый редактор:
Ну а дальше уже по классической схеме – сначала добавляем саму сущность в шапку:
А затем вызываем ее в документе, в месте, которое отображалось в импорте. В моем случае, единственная строка – hello world, а значит я просто найду тег с ней в документе и заменю на сущность:
После этого сохраняем и закрываем файл. Далее архив нужно упаковать обратно. По сути, для тестов будет достаточно упаковать туда один только document.xml файл, самой функциональности документа это не навредит.
Сделать это можно так же, при помощи дефолтной команды zip:
Получаем готовый docx документ. Далее пытемся импортировать его как резюме, и:
Получаем содержимое файла etc/passwd на сервере.
Кратко, подведем итог почему так произошло:
Функция импорта из документа работала с форматом docx, просто распаковывая его и работая уже с содержимым xml-файлов. Но разработчики не учли, что в этих xml-файлах может содержаться вредносный код. Это и привело к XML-иньекции. (После обнаружения, уязвимость, разумеется, была пропатчена)
Итог:
Итак, мы разобрали XML-иньекции. Какой вывод можно сделать ? XML-иньекции – сейчас достаточно редки. Вероятность встретить классические кейсы крайне мала. Для того, чтобы найти что-то подобное на целелвом сайте атакующему должно очень сильно повезти. Слишком много звезд должно сойтись, чтобы уязвимость можно было нормально раскрутить до какого-то ощутимого профита. Там и иньекция должна быть не слепой, и ошибки разработчик должен допустить достаточно глупые. Поэтому уязвимость, по моему скромному мнению, хоть и заслуживает внимания, все же на практике как правило себя не оправдывает и встречается довольно редко. Так что, знать об уязвимости стоит, но врятли вы ее часто будете встречать на деле. Однако, знания, как известно, лишними не бывают, и лучше знать, но не наткнуться, чем наткнуться и не знать. Кто знает, может однажды, именно такая уязвимость как XML-иньекция станет ключом к нужному вам серверу.
На этом, с темой XML-иньекций у меня все, всем добра !
© Urob0ros, специально для форума xss.pro