Следующая новость
Предыдущая новость

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box

20.11.2019 12:54
В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box

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

  • В королевстве PWN
  • Разведка
  • Сканирование портов
  • Веб — порт 1111
  • Анализ tiny-web-server
  • Изменения в исходном коде tiny.c
  • Найти уязвимую строку
  • Разработка эксплоита
  • pwntools для Python 3
  • От грубого шелла до SSH — порт 22
  • Исследование окружения
  • PrivEsc: www → smasher
  • Криптооракулы, или атака Padding Oracle
  • Разработка эксплоита
  • Содержимое crackme.py
  • PrivEsc: smasher → root
  • Анализ checker
  • strace
  • Гонка за root.txt
  • Эпилог
  • Анализ tiny.c с помощью PVS-Studio

В этой статье тебя ждут: низкоуровневая эксплуатация веб-сервера со срывом стека и генерацией шелл-кода на лету с помощью древней магии pwntools; атака Padding Oracle на питоновское приложение для вскрытия шифртекста AES-CBC, а также реверс-инжиниринг исполняемого файла с атрибутом SUID для повышения привилегий в системе до локального суперпользователя.

Все это мы проделаем на пути к root-флагу виртуалки Smasher (уровень сложности Insane — 7,6 балла из 10) с CTF-площадки Hack The Box. Поскольку речь в основном пойдет о срыве стека, это будет отличным завершением для нашего цикла «В королевстве PWN».

HTB — Smasher

В королевстве PWN

В этом цикле статей мы изучаем разные аспекты атак типа «переполнение стека». Читай также:

  • «Препарируем классику переполнения буфера в современных условиях»
  • «Обходим DEP и брутфорсим ASLR на виртуалке с Hack The Box»
  • «ROP-цепочки и атака Return-to-PLT в CTF Bitterman»

Разведка

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

Я продолжаю извращаться с методами обнаружения открытых портов, и в этот раз будем пользоваться связкой из Masscan и Nmap. Masscan, к слову, на сегодняшний день самый быстрый из асинхронных сканеров портов. Ко всему прочему он опирается на собственное видение стека TCP/IP и, по словам разработчика, может просканировать весь интернет за шесть минут с одного хоста.

root@kali:~# masscan --rate=1000 -e tun0 -p1-65535,U:1-65535 10.10.10.89 > ports

Первой командой я инициирую сканирование всего диапазона портов (в том числе UDP) IP-адреса, по которому живет Smasher, и перенаправляю результат в текстовый файл.

root@kali:~# ports=`cat ports | awk -F " " '{print $4}' | awk -F "/" '{print $1}' | sort -n | tr "n" ',' | sed 's/,$//'`
root@kali:~# nmap -n -Pn -sV -sC -oA nmap/smasher -p$ports 10.10.10.89

Далее с помощью стандартных средств текстового процессинга в Linux обрабатываю результаты скана, чтобы найденные порты хранились одной строкой через запятую, сохраняю эту строку в переменной ports и спускаю с поводка Nmap.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Сканирование портов ВМ Smasher

По мнению Nmap, мы имеем дело с Ubuntu 16.04 (Xenial). Оно основано на информации о баннере SSH. Постучаться же можно в порты 22 и 1111. На последнем, кстати, висит некий shenfeng tiny-web-server — вот его мы и отправимся исследовать в первую очередь.

Веб — порт 1111

Браузер

По адресу http://10.10.10.89:1111/ тебя встретит листинг корневой директории веб-сервера.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Листинг корневой директории веб-сервера

Интересно, что страница index.html существует, но редиректа на нее нет — вместо этого открывается список файлов каталога. Запомним это.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Форма авторизации /index.html

Если мы перейдем на /index.html вручную, то увидим заглушку для формы авторизации, с которой никак нельзя взаимодействовать (можно печатать в полях ввода, но кнопка Login не работает). Забавно, что оба поля для ввода называются input.email.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Наименования полей формы авторизации

A tiny web server in C

Если поискать shenfeng tiny-web-server в Сети, по первой же ссылке в выдаче результатов можно найти репозиторий проекта на GitHub.

Сразу же бросаются в глаза предупреждения, что код небезопасен: первое в самом описании сервера (как единственная его «антифича»), второе — в открытых issues.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Проблема безопасности tiny-web-server (Path Traversal)

Если верить описанию, то tiny-web-server подвержен Path Traversal, а возможность просматривать листинги директорий как будто шепчет тебе на ухо: «Так оно и есть…»

Анализ tiny-web-server

Проверим выполнимость Path Traversal. Так как Firefox любит исправлять синтаксически некорректные конструкции в адресной строке (в частности, резать префиксы вида ../../../), то я сделаю это с помощью nc, как показано в issue.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
PoC уязвимости выхода за корневую директорию веб-сервера

Что и требовалось доказать — у нас есть возможность читать файлы на сервере!

Что дальше? Осмотримся. Если дублировать первичный слеш для доступа к каталогам, сервер подумает, что таким образом мы обращаемся к корневой директории, — и разведку можно будет провести прямо из браузера.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Содержимое /home

В /home нам доступна всего одна директория — /www.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Содержимое /home/www

Из интересного здесь — скрипт restart.sh для перезапуска инстанса процесса сервера, а также сама директория с проектом.

#!/usr/bin/env bash  ## Please don’t edit this file let others players have fun  cd /home/www/tiny-web-server/ ps aux | grep tiny | awk '{print $2}' | xargs kill -9 nohup ./tiny public_html/ 1111 2>&1 > /dev/null & 
В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Содержимое /home/www/tiny-web-server

Чтобы не мучиться с загрузкой каждого файла по отдельности, я клонирую директорию /home/www целиком с помощью wget, исключив каталог .git, — различия в коде веб-сервера по сравнению с GitHub-версией мы узнаем чуть позже другим способом.

root@kali:~# wget --mirror -X home/www/tiny-web-server/.git http://10.10.10.89:1111//home/www/

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Клонирование /home/www с помощью wget

Три файла представляют для нас интерес: Makefile, tiny и tiny.c.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Листинг локальной копии /home/www

В Makefile содержатся инструкции для сборки исполняемого файла.

CC = c99 CFLAGS = -Wall -O2  ## LIB = -lpthread  all: tiny  tiny: tiny.c     $(CC) $(CFLAGS) -g -fno-stack-protector -z execstack -o tiny tiny.c $(LIB)  clean:     rm -f *.o tiny *~ 

Флаги -g -fno-stack-protector -z execstack намекают нам на предполагаемый «по сюжету» вектор атаки — срыв стека, который, надеюсь, уже успел тебе полюбиться.

Файл tiny — сам бинарник, который развернут на Smasher.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Сводка безопасности исполняемого файла tiny (checksec)

У нас есть исполняемый стек, сегменты с возможностью записи и исполнения произвольных данных и активный механизм FORTIFY — последний, правда, ни на что не повлияет в нашей ситуации (подробнее о нем можно прочесть в первой части цикла, где мы разбирали вывод checksec). Плюс нужно помнить, что на целевом хосте, скорее всего, активен механизм рандомизации адресного пространства ASLR.

Прежде чем перейти непосредственно к сплоитингу, посмотрим, изменил ли как-нибудь автор машины исходный код tiny.c (сам файл я положу к себе на гитхаб, чтобы не загромождать тело статьи).

Изменения в исходном коде tiny.c

Если нужно построчно сравнить текстовые файлы, я предпочитаю расширение DiffTabs для Sublime Text, где — в отличие от дефолтного diff — есть подсветка синтаксиса. Однако, если ты привык работать исключительно из командной строки, colordiff станет удобной альтернативой.

Выдернем последнюю версию tiny.c с гитхаба (будем звать ее tiny-github.c) и сравним с тем исходником, который мы захватили на Smasher.

root@kali:~# wget -qO tiny1-github.c https://raw.githubusercontent.com/shenfeng/tiny-web-server/master/tiny.c
root@kali:~# colordiff tiny-github.c tiny.c

166c166 <     sprintf(buf, "HTTP/1.1 200 OKrn%s%s%s%s%s", --- >     sprintf(buf, "HTTP/1.1 200 OKrnServer: shenfeng tiny-web-serverrn%s%s%s%s%s", 233a234,236 >     int reuse = 1; >     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) >         perror("setsockopt(SO_REUSEADDR) failed"); 234a238,239 >     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0) >         perror("setsockopt(SO_REUSEPORT) failed"); 309c314 <     sprintf(buf, "HTTP/1.1 %d %srn", status, msg); --- >     sprintf(buf, "HTTP/1.1 %d %srnServer: shenfeng tiny-web-serverrn", status, msg); 320c325 <         sprintf(buf, "HTTP/1.1 206 Partialrn"); --- >         sprintf(buf, "HTTP/1.1 206 PartialrnServer: shenfeng tiny-web-serverrn"); 346c351,355 < void process(int fd, struct sockaddr_in *clientaddr){ --- > int process(int fd, struct sockaddr_in *clientaddr){ >     int pid = fork(); >     if(pid==0){ >     if(fd < 0) >       return 1; 377a387,389 >     return 1; >   } > return 0; 407a420 >     int copy_listen_fd = listenfd; 417,420c430 < <     for(int i = 0; i < 10; i++) { <         int pid = fork(); <         if (pid == 0) {         //  child --- >     signal(SIGCHLD, SIG_IGN); 421a432 > 423c434,437 <                 process(connfd, &clientaddr); --- >               if(connfd > -1)  { >                 int res = process(connfd, &clientaddr); >               if(res == 1) >                       exit(0); 424a439,440 >               } > 426,437d441 <         } else if (pid > 0) {   //  parent <             printf("child pid is %dn", pid); <         } else { <             perror("fork"); <         } <     } < <     while(1){ <         connfd = accept(listenfd, (SA *)&clientaddr, &clientlen); <         process(connfd, &clientaddr); <         close(connfd); <     } 438a443 > 

Незначительные изменения:

  • добавлена обработка ошибок (233a234, 234a238);
  • в строчках баннеров веб-сервера появилось имя разработчика, что облегчает атакующему идентификацию ПО на этапе сканирования хоста (166c166, 320c325).

Важные изменения: модифицирована логика обработки запросов клиента (все, что касается функции process и создания форков). Если в tiny-github.c реализована многопоточность с помощью концепции PreFork, когда мастер-процесс спавнит дочерние в цикле от 0 до 9, то в tiny.c родитель форкается только один раз — и уже не в теле main, а в самой функции process. Полагаю, это было сделано, чтобы ослабить нагрузку на сервер — ведь ВМ атакует множество людей одновременно. Ну а нам это только на руку, потому что дебажить многопоточные приложения — то еще удовольствие.

Найти уязвимую строку

На одной из моих вузовских практик преподаватель поставил такую задачу: без доступа в Сеть с точностью до строки найти в исходном коде пакета OpenSSL место, ответственное за нашумевшую уязвимость Heartbleed (CVE-2014-0160). Разумеется, в большинстве случаев нельзя однозначно обвинить во всех бедах одну-единственную строку, но всегда можно (и нужно) выделить для себя место в коде, от которого ты будешь отталкиваться при атаке.

Найдем такую строку в tiny.c. В формате статьи трудно анализировать исходные коды без нагромождения повторяющейся информации — поэтому я представлю анализ в виде цепочки «прыжков» по функциям (начиная от main и заканчивая уязвимостью), а ты потом сам проследишь этот путь в своем редакторе.

main() { int res = process(connfd, &clientaddr); } ==> process() { parse_request(fd, &req); } ==> parse_request() { url_decode(filename, req->filename, MAXLINE); } 

Функция url_decode принимает три аргумента: два массива строк (источник — filename и назначение — req->filename) и количество копируемых байтов из первого массива во второй. В нашем случае это константа MAXLINE, равная 1024.

void url_decode(char* src, char* dest, int max) {     char *p = src;     char code[3] = { 0 };     while(*p && --max) {         if(*p == '%') {             memcpy(code, ++p, 2);             *dest++ = (char)strtoul(code, NULL, 16);             p += 2;         } else {             *dest++ = *p++;         }     }     *dest = ''; } 

Алгоритм функции тривиален. Клиент запрашивает у сервера файл. Если строка с именем этого файла содержит данные в Percent-encoding (их можно определить по символу %), функция выполняет декодирование и помещает соответствующий байт в массив назначения. В противном случае происходит простое побайтовое копирование. Однако проблема в том, что локальный массив filename имеет размер MAXLINE (то есть 1024 байт), а вот поле req->filename структуры http_request располагает лишь 512 байтами.

typedef struct {     char filename[512];     off_t offset;              /* for support Range */     size_t end; } http_request; 

Налицо классический Out-of-bounds Write (CWE-787: запись за пределы доступной памяти) — он и делает возможным срыв стека.

В эпилоге мы посмотрим на анализ трассировки этого кода, а пока подумаем, как можно использовать уязвимое место tiny.c.

Разработка эксплоита

Сперва насладимся моментом, когда сервер tiny крашится. Так как с ошибкой сегментации упадет дочерний процесс программы, привычного алерта Segmentation fault в окне терминала мы не увидим. Чтобы убедиться, что процесс отработал некорректно и завершился сегфолтом, я открою журнал сообщений ядра dmesg (с флагом -w) и запрошу у сервера (несуществующий) файл с именем из тысячи букв A.

root@kali:~# ./tiny 1111
root@kali:~# dmesg -w
root@kali:~# curl localhost:1111/$(python -c 'print "A"*1000')

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Подтверждение ошибки сегментации процесса tiny

Класс: видим, что запрос выбивает child-процесс c general protection fault (или segmentation fault в нашем случае).

Поиск точки перезаписи RIP

Запустим исполняемый файл сервера в отладчике GDB.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box

INFO

Классический GDB без обвесов по умолчанию следит за выполнением родительского процесса, однако установленный ассистент PEDA будет мониторить дочерний процесс, если при выполнении был форк. Это эквивалентно настройке set follow-fork-mode child в оригинальном GDB.

root@kali:~# gdb-peda ./tiny
Reading symbols from ./tiny...
gdb-peda$ r 1111
Starting program: /root/htb/boxes/smasher/tiny 1111
listen on port 1111, fd is 3

Теперь важный момент: я не могу пользоваться циклическим паттерном де Брёйна, который предлагает PEDA, ведь он содержит символы '%' — а они, если помнишь, трактуются сервером как начало URL-кодировки.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Циклическая последовательность, сгенерированная при помощи GDB PEDA

Значит, нам нужен другой генератор. Можно пользоваться msf-pattern_create -l <N> и msf-pattern_offset -q <0xFFFF>, чтобы создать последовательность нужной длины и найти смещение. Однако я предпочитаю модуль pwntools, который работает в разы быстрее.

В королевстве PWN. Атака ret2bss, криптооракулы и реверс-инжиниринг на виртуалке Smasher с Hack The Box
Циклические последовательности, сгенерированные при помощи MSF и pwntools

Как мы видим, ни один из инструментов не использует «плохие» символы, поэтому для генерации вредоносного URL можно юзать любой из них.

root@kali:~# curl localhost:1111/$(python -c 'import pwn; print pwn.cyclic(1000)')
File not found

Мы отправили запрос на открытие несуществующей страницы при помощи curl — а теперь смотрим, какое значение осело в регистре RSP, и рассчитываем величину смещения до RIP.

gdb-peda$ x/xw $rsp
0x7fffffffdf48: 0x66616172
root@kali:~# python -c 'from pwn import *; print cyclic_find(unhex("66616172")[::-1])'
568

Ответ: 568.

После выхода из отладчика хорошо бы принудительно убить все инстансы веб-сервера — ведь однозначно завершился только child-процесс.

root@kali:~# ps aux | grep tiny | awk '{print $2}' | xargs kill -9

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

1 год

7690 р.

1 месяц

720 р.

Я уже участник «Xakep.ru»

Источник

Последние новости