HTB Timing. Пентестим веб-сервер на PHP

HTB Timing. Пентестим веб-сервер на PHP

the Matrix

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

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

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

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

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

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

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

На SSH нам ловить нечего, про­пус­каем его.

Пос­коль­ку вна­чале у нас нет учет­ных дан­ных, нет и смыс­ла изу­чать служ­бы, которые всег­да тре­буют авто­риза­ции (нап­ример, SSH). Единс­твен­ное, что мы можем делать здесь, — это переби­рать пароли брут­форсом, но машины с HTB поч­ти всег­да мож­но прой­ти по‑дру­гому. В жиз­ни таких вари­антов может не быть, к тому же есть шан­сы подоб­рать пароль или получить его при помощи соци­аль­ной инже­нерии.

Пос­мотрим, что нам покажет веб‑сер­вер. При обра­щении к нему про­исхо­дит редирект на стра­ницу /login.php, где нас встре­чает фор­ма авто­риза­ции.

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

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

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

За­пус­каем его с нуж­ными парамет­рами:

Наш­ли мно­го фай­лов, теперь прос­каниру­ем и скры­тые катало­ги.

В ито­ге находим катало­ги для хра­нения скрип­тов и изоб­ражений. Боль­ше нам ничего не дос­тупно. Ска­ниро­вание фай­лов бэкапов и под­доменов ничего не дало. Но мы еще не поис­кали парамет­ры! Для ска­ниро­вания логич­но выб­рать стра­ницу image.php, которая пред­положи­тель­но дол­жна воз­вра­щать изоб­ражения. Так как мы не зна­ем, что будет переда­но в качес­тве зна­чения парамет­ра, поп­робу­ем передать само наз­вание стра­ницы в надеж­де получить какую‑нибудь ошиб­ку.

Мы наш­ли один параметр — img. То есть мы можем зап­росить файл с кар­тинкой по его наз­ванию. Поп­робу­ем таким спо­собом ута­щить какой‑нибудь сис­темный файл, задав отно­ситель­ный путь.

Нас пой­мали за руку!

Здесь, судя по все­му, исполь­зуют­ся какие‑то филь­тры, которые меша­ют нам читать любой файл. Я поп­робовал раз­ные вари­анты обер­ток для парамет­ра и обна­ружил, что сра­баты­вает зап­рос вот такого вида:

Local file inclusion (LFI) — тех­ника, которая исполь­зует­ся для получе­ния дос­тупа к фай­лам в сис­теме через веб‑сер­вер. Что­бы сер­вер отоб­разил файл, а не попытал­ся его выпол­нить, ему нуж­но передать «обер­тку» — коман­ды, которые закоди­руют файл. Пос­ле его получе­ния оста­нет­ся лишь рас­кодиро­вать его обратно. Сущес­тву­ет мно­жес­тво го­товых обер­ток, которые ты можешь при­менять при пен­тесте.

Со­дер­жимое этой стра­ницы, получен­ной в ответ, будет закоди­рова­но в Base64. Декоди­ровать мож­но пря­мо Burp, нажав Ctrl-Shift-B.

Так как мы можем получить код любой стра­ницы, идем по поряд­ку и заг­лядыва­ем в исходный код стра­ницы login.php.

В нем ничего инте­рес­ного нет, кро­ме под­клю­чения фай­ла db_conn.php (стро­ка 10). Здесь мы находим учет­ку для под­клю­чения к базе дан­ных. Конеч­но же, прос­мотрим и его.

Па­роль пока ни к чему не подошел, поэто­му копа­ем даль­ше. Перей­дем к фай­лам, о которых мы уже зна­ем. Нач­нем с upload.php.

В самом начале под­клю­чает­ся файл admin_auth_check.php. Затем зада­ются необ­ходимые парамет­ры для заг­ружен­ного фай­ла, в том чис­ле и file_name. Имя фай­ла соз­дает­ся по сле­дующе­му алго­рит­му: берет­ся стро­ка '$file_hash', затем добав­ляет­ся текущее вре­мя (резуль­тат выпол­нения фун­кции time()), все это кон­верти­рует­ся в хеш MD5, а даль­ше добав­ляет­ся знак ниж­него под­черки­вания и имя фай­ла, которое исполь­зовалось при заг­рузке. При этом файл дол­жен иметь рас­ширение jpg. А в фай­ле admin_auth_check.php толь­ко срав­нива­ется роль поль­зовате­ля.

Ес­ли бы $file_hash кто‑то по ошиб­ке не обер­нул в кавыч­ки, то под­ста­вилось бы зна­чение перемен­ной, получен­ное от PHP-фун­кции uniqid(). Раз­гадать уни­каль­ный иден­тифика­тор у нас бы не выш­ло, а без него единс­твен­ной прег­радой будет вывод фун­кции time().

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

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

Нам откры­вает­ся новая фун­кция — изме­нение про­филя.

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

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

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

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

Мы зна­ем, что это дол­жен быть файл с рас­ширени­ем jpg. Но вот толь­ко его содер­жимое не про­веря­ется, поэто­му мы можем записать туда код на PHP и затем поп­робовать выпол­нить. Запишем сле­дующий прос­той PHP-шелл, выпол­няющий при­нятую коман­ду, и заг­рузим файл на сер­вер.

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

Единс­твен­ная перемен­ная, которую нам оста­лось получить, — зна­чение фун­кции time(). Эта фун­кция воз­вра­щает количес­тво секунд, про­шед­ших с 00:00:00 01.01.1970. И если мы зна­ем вре­мя заг­рузки фай­ла, уста­нов­ленное на сер­вере, мы смо­жем получить это зна­чение. Так как вся работа выпол­няет­ся через Burp, в исто­рии зап­росов най­дем HTTP-заголо­вок отве­та сер­вера. В заголов­ке Date будет ука­зано нуж­ное нам вре­мя.

Те­перь мы можем получить зна­чение MD5 от сло­жения всех строк:

Нам нуж­но обра­щать­ся к фай­лу вот с таким име­нем:

Поп­робу­ем с помощью нашего хеша выпол­нить базовую коман­ду id.

Ко­ман­да успешно выпол­нена, что озна­чает получе­ние дос­тупа к хос­ту.

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

Ко­пиру­ем архив в каталог веб‑сер­вера и лег­ко ска­чива­ем через бра­узер.

В архи­ве при­сутс­тву­ет каталог с рас­ширени­ем git. Это поз­волит нам получить дос­туп к исто­рии изме­нений фай­лов.

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

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

Пер­вым делом про­веря­ем наибо­лее веро­ятные мес­та повыше­ния при­виле­гий: нас­трой­ки sudoers, при­ложе­ния с выс­тавлен­ным битом SUID, прос­лушива­емые на локал­хосте пор­ты. Про­верим sudoers коман­дой sudo -l.

В нас­трой­ках про­писан при­виле­гиро­ван­ный запуск /usr/bin/netutils без вво­да пароля (NOPASSWD). Прос­мотрим тип фай­ла.

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

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

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

Пос­мотрим, что про­исхо­дит с про­цес­сами в сис­теме при выпол­нении это­го при­ложе­ния. Для отсле­жива­ния про­цес­сов будем исполь­зовать pspy64. Заг­рузим его на хост:

И выпол­ним. В выводе видим запуск скрип­та, но, что более инте­рес­но, пос­ле ука­зания адре­са для заг­рузки исполь­зует­ся прог­рамма axel в кон­тек­сте поль­зовате­ля с UID=0, а это поль­зователь root.

Я сра­зу поп­робовал выпол­нить инъ­екцию коман­ды ОС, но это ничего не дало.

Од­нако мы можем кон­фигури­ровать axel и управлять некото­рыми его парамет­рами, к при­меру име­нем фай­ла и катало­гом для его сох­ранения. Недол­го раз­мышляя, про­буем сох­ранить файл как пуб­личный SSH-ключ поль­зовате­ля root. Для это­го в домаш­нем катало­ге текуще­го поль­зовате­ля сох­раним файл .axelrc со сле­дующим содер­жимым:

На локаль­ном хос­те сге­нери­руем пару клю­чей (ssh-keygen) и пере­име­нуем пуб­личный, что­бы он называл­ся index.. Запус­тим прос­той веб‑сер­вер на Python:

А затем обра­тим­ся к нему из тес­тиру­емо­го при­ложе­ния.

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

Ма­шина зах­вачена, и у нас есть флаг рута.


Источник

Наши проекты:

- Кибер новости: the Matrix
- Хакинг: /me Hacker
- Кодинг: Minor Code

Report Page