Взлом веб-сервера на PHP

Взлом сервера PHP

В этой статье рассмотрим прохождение уязвимой машины Timing Hack The Box, в рамках которой будем взламывать веб-сервер на PHP. Для получения флага мы будем сканировать порты, экс­плу­атировать уяз­вимос­ти LFI и заг­рузим шел­л.

Еще по теме: Как взломать сайт WordPress

Лучше подключаться к машине HTB с помощью VPN. И желательно не делать это со своего личного компа, на котором хранится чувствительная информация.

Взлом веб-сервера на PHP

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

Начнем со сканирования портов. Это стан­дар­тная операция при любом пентесте. Сканирование портов позволит определить, какие служ­бы на машине при­нима­ют соеди­нение.

Для этого отлично подходит популярный сканер Nmap. Следующий скрипт улучшит резуль­таты сканирования:

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

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

Сканер нашел два откры­тых пор­та:

  • 80 — веб‑сер­вер Apache 2.4.29;
  • 22 — служ­ба OpenSSH 7.6p1.

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

Брутфорс учеток

У нас пока нет учет­ных дан­ных, поэтому нет смыс­ла в анализе служ­б, которые как правило тре­буют авто­риза­ции (нап­ример, SSH). Единс­твен­ное, что можно сделать на данном этапе — перебрать пароли брут­ом, но уязвимые машины с Hack The Boxt практически всегда имеют другие решения. В реальности таких вари­антов может не быть, но можно всегда использовать социальную инженерию.

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

Фор­ма авто­риза­ции login.php
Фор­ма авто­риза­ции login.php

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

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

Пер­вое дей­ствие при тес­тирова­нии безопас­ности веб‑при­ложе­ния — это ска­ниро­вание методом перебо­ра катало­гов. Для это­й цели вы можете исполь­зовать прог­раммы вро­де DIRB и dirsearch.

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

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

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

Ре­зуль­тат ска­ниро­вания PHP-фай­лов
Ре­зуль­тат ска­ниро­вания PHP-фай­лов

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

Ска­ниро­вание скры­тых катало­гов
Ска­ниро­вание скры­тых катало­гов

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

Попробуем поискать парамет­ры. Для ска­ниро­вания разумеется выбираем стра­ницу image.php, которая по идее дол­жна воз­вра­щать изоб­ражения. Так как мы пока не зна­ем, что именно будет переда­но в качес­тве зна­чения парамет­ра, попытается передать само наз­вание стра­ницы, надеясь получить какую-то ошиб­ку.

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

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

HTB Timing, Атака обнаружена
Атака обнаружена

Попытка не удалась. Нас атаку обнаружили!

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

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

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

Код стра­ницы index.php
Код стра­ницы index.php

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

Ис­ходный код login.php
Ис­ходный код login.php

Наше внимание привлекает строка 10 — под­клю­чение фай­ла db_conn.php. Там нашлась учет­ная запись для под­клю­чения к БД. Отроем и его.

Ис­ходный код db_conn.php
Ис­ходный код db_conn.php

Па­роль ни к чему не подходит, поэто­му продолжаем копать.

Переходим к известным фай­лам. Нач­инаем с upload.php.

Ис­ходный код upload.php
Ис­ходный код upload.php

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

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

Ис­ходный код admin_auth_check.php
Ис­ходный код admin_auth_check.php

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

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

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

Па­нель авто­ризо­ван­ного поль­зовате­ля
Па­нель авто­ризо­ван­ного поль­зовате­ля

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

Фор­ма изме­нения про­филя
Фор­ма изме­нения про­филя

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

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

 

Ис­ходный код update.php
Ис­ходный код update.php

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

Но­вый зап­рос
Но­вый зап­рос

 

От­вет сер­вера
От­вет сер­вера

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

Глав­ная стра­ница адми­нис­тра­тора
Глав­ная стра­ница адми­нис­тра­тора

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

Фор­ма заг­рузки фай­ла
Фор­ма заг­рузки фай­ла

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

Запишем сле­дующий прос­той PHP-шелл, выпол­няющий при­нятую коман­ду, и заг­рузим файл на сер­вер.

Со­обще­ние о заг­рузке фай­ла
Со­обще­ние о заг­рузке фай­ла

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

Код фор­мирова­ния име­ни заг­ружен­ного фай­ла
Код фор­мирова­ния име­ни заг­ружен­ного фай­ла

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

Так как вся работа выпол­няет­ся через Burp, в исто­рии зап­росов най­дем HTTP-заголо­вок отве­та сер­вера. В заголов­ке Date будет ука­зано нуж­ное нам вре­мя.

HTTP-заголо­вок отве­та сер­вера при заг­рузке фай­ла
HTTP-заголо­вок отве­та сер­вера при заг­рузке фай­ла

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

Рас­чет пер­вой час­ти име­ни фай­ла
Рас­чет пер­вой час­ти име­ни фай­ла

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

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

Вы­пол­нение коман­ды id
Вы­пол­нение коман­ды id

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

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

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

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

Ска­чива­ние исходных кодов через бра­узер
Ска­чива­ние исходных кодов через бра­узер

 

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

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

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

Из­менение в фай­ле db_conn.php
Из­менение в фай­ле db_conn.php

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

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

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

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

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

Оп­ределе­ние типа фай­ла /usr/bin/netutils
Оп­ределе­ние типа фай­ла /usr/bin/netutils

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

Со­дер­жимое фай­ла /usr/bin/netutils
Со­дер­жимое фай­ла /usr/bin/netutils

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

Ме­ню при­ложе­ния
Ме­ню при­ложе­ния

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

Со­обще­ние о заг­рузке фай­ла
Со­обще­ние о заг­рузке фай­ла

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

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

Ло­ги pspy
Ло­ги pspy

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

Тес­тирова­ние OS Command Injection
Тес­тирова­ние OS Command Injection

Од­нако мы можем кон­фигури­ровать axel и управлять некото­рыми его парамет­рами, к при­меру име­нем фай­ла и катало­гом для его сох­ранения.

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

Взлом веб-сервера PHP. Файл кон­фигура­ций axel
Файл кон­фигура­ций axel

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

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

Взлом сервера PHP. За­пись SSH-клю­ча
За­пись SSH-клю­ча

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

Взлом веб-сервера на PHP. Флаг рута
Взлом веб-сервера на PHP. Флаг рута

Мы получили флаг рута. Веб-сервер на PHP взломан.

Заключение

Се­год­ня мы с вами прошли путь от обычного ска­ниро­вания сай­та до экс­плу­ата­ции уяз­вимос­ти типа LFI и заг­рузки шел­ла. Надеюсь вам понравился увлекательное задание Timing с пло­щад­ки Hack The Box.

Полезные ссылки:

ВКонтакте
OK
Telegram
WhatsApp
Viber

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *