Яйца? Охота? О чем мы говорим?

При разработке эксплойтов Egg - это полноценная полезная нагрузка шелл-кода, которая обычно имеет в начале nop sled. Начало полезной нагрузки (обычно салазок nop) будет иметь особую сигнатуру, которую мы будем использовать, чтобы определить, где наш шелл-код помещается в памяти. Иногда вы не можете заранее знать, где ваш шелл-код будет размещен в памяти. Таким образом, вы можете использовать подпись яйца (обычно первые 8 байтов полезной нагрузки), чтобы найти точное место.

Egg-Hunter - это часть шелл-кода, которая ищет определенную подпись в виртуальном адресном пространстве процесса (также известном как VAS) и переходит к полезной нагрузке.

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

Общий вариант использования:

1- Мы предоставляем шеллкоду фактическую полезную нагрузку, которую мы хотим выполнить (например, обратная оболочка).

2- Этот шеллкод будет помещен в случайный раздел VAS.

3- Затем мы используем уязвимость и запускаем шелл-код охотника за яйцами.

4- Охотник за яйцами просматривает весь VAS в поисках большей полезной нагрузки. Как только он находит полезную нагрузку, он прыгает в нее.

5- Выполняется большая и окончательная полезная нагрузка. Это дает нам возможность использовать большую полезную нагрузку, которую невозможно было бы использовать иначе.

В этом примере мы используем одного охотника за яйцами, но учтите, что этот метод может быть связан несколько раз для выполнения действительно больших поэтапных полезных нагрузок.

Анатомия охотника за яйцами

Охотник за яйцами должен обладать следующими свойствами:

1- Он должен быть прочным

Он должен иметь возможность переходить в недопустимые области памяти без сбоя приложения. Следовательно, он должен каким-то образом управлять разыменованием недопустимых адресов и исключений, возникающих, например, при попытке чтения из привилегированной / критической области памяти.

2- Он должен быть маленьким

Основное предназначение охотника за яйцами - разместить там, где не поместится никакая другая полезная нагрузка. Если бы мы могли уместить нашу обычную полезную нагрузку оболочки, зачем нам это нужно? Итак, естественно, размер - один из самых важных аспектов охотника за яйцами.

3- Это должно быть быстро

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

Анатомия яйца

Яйцо может быть любой полезной нагрузкой, первые 8 байтов которой мы возьмем в качестве подписи. В общем, первые 8 байтов являются частью салазок nop (для повышения надежности), поэтому мы сосредоточимся на них.

; Signature sample 1 (8 bytes long ) 
; String representation "\x90\x50\x90\x50\x90\x50\x90\x50"
; Hexadecimal 32-bit 0x90509050 0x90509050
; Hexadecimal 64-bit 0x9050905090509050
; Assembly code:
90  nop
50  push rax
90  nop
50  push rax
90  nop
50  push rax
90  nop
50  push rax
-- -- -- -- --
; Signature sample 2 (8 bytes long ) 
; String representation "\x99\x99\x90\x99\x99\x99\x90\x99"
; Hexadecimal 32-bit 0x99999099 0x99999099
; Hexadecimal 64-bit 0x9999909999999099
; Assembly code:
99  cdq
99  cdq
90  xchg rax, rax ; same as nop
99  cdq
99  cdq
99  cdq
90  xchg rax, rax ; same as nop
99  cdq

1- Размер

Яйцо обычно имеет длину 8 байт. Мы, конечно, можем настроить это, сделав его больше или короче в зависимости от обстоятельств.

2- Тип

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

Реализация охотника за яйцами в Linux / x64

В Linux, когда системный вызов обнаруживает недопустимый адрес памяти, большинство из них возвращает код ошибки EFAULT в регистр RAX. Это очень важно, так как это будет наш способ узнать, что мы зашли не в то место, и это будет наш ключевой механизм для повышения надежности ловца яиц. Более подробную информацию о кодах ошибок вы можете найти здесь. Давайте подтвердим это и в процессе соберем ценность EFAULT. Для этого мы можем использовать этот небольшой фрагмент сборки, который вызывает системный вызов доступа для адреса 0x00, который завершится ошибкой.

BITS 64
global _start
section .text
_start:
    mov rax, 0x15   ; Syscall access number
    mov rdi, 0x00   ; Address to check : 0x00
    mov rsi, 0x00   ; Mode
    syscall

После компиляции и связывания мы приступаем к тесту:

Итак, EFAULT - 0xfffffffffffffff2 (-14).

А теперь напишем нашего охотника за яйцами. Нам нужно проверить каждый адрес, чтобы убедиться, что он действителен для нашего процесса, в противном случае мы можем пропустить всю страницу, поскольку страница является минимальной выделяемой единицей в памяти. Чтобы получить размер страницы, мы можем использовать команду getconf. В моем случае я использую виртуальную машину ubuntu64, которая дает: 4096

> getconf PAGE_SIZE
> 4096
This can be easily converted to hex using radare2 utility rax2
> rax2 (getconf PAGE_SIZE)
> 0x1000

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

Давайте проверим это!

В следующем видео я прохожу весь процесс извлечения шеллкода как для охотника за яйцами, так и для полезной нагрузки. Затем я использую тестовый скелет, написанный на C, чтобы продемонстрировать функциональность.

Полезная нагрузка, которую я использую, - это написанная мной настраиваемая обратная оболочка, защищенная паролем. Вы можете найти исходный код в этом сообщении в блоге. Полезная нагрузка будет подключена к tcp: //127.0.0.1: 4444 и предоставит оболочку после пароля LETMEIN! вводится.

Исходный код тестера egg-hunter, написанный на C, можно найти здесь.

Вот и все, ребята! Вот несколько ресурсов, которые могут быть полезны, если вы изо всех сил пытаетесь понять, как работают охотники за яйцами:



Это сообщение в блоге создано для выполнения требований сертификации SecurityTube Linux Assembly Expert
Идентификатор студента: SLAE64–1326
Исходный код можно найти здесь