Русский
Русский
English
Статистика
Реклама

Шелл-код

Перевод bdshemu эмулятор шелл-кода в Bitdefender

16.11.2020 16:04:47 | Автор: admin
Совсем скоро, 19 ноября, у нас стартует курс Этичный хакер, а специально к этому событию мы подготовили этот перевод о bdshemu написанном на языке C эмуляторе с открытым исходным кодом в Bitdefender для обнаружения эксплойтов на 32- и 64-битной архитектуре. Эмулятор очень прост, а благодаря нацеленности на уровень инструкций он работает с любой операционной системой. Кроме того, этот эмулятор зачастую сохраняет расшифрованный эксплойт в бинарный файл. Подробности и пример обнаружения Metasploit под катом, ссылка на репозиторий проекта на Github в конце статьи.





Введение


Обнаружение эксплойтов одна из основных сильных сторон Hypervisor Memory Introspection (HVMI). Возможность мониторинга гостевых страниц физической памяти на предмет различных видов доступа, таких как запись или выполнение, позволяет HVMI накладывать ограничения на критические области памяти: например, страницы стека или кучи могут быть помечены как невыполняемыми на уровне EPT, поэтому, когда эксплойту удается получить доступ к произвольному выполнению кода, вмешивается логика интроспекции и блокирует выполнение шелл-кода.

Теоретически перехвата попыток выполнения из областей памяти, например стека или кучи, должно быть достаточно, чтобы предотвратить действия большинства эксплойтов. Реальная жизнь часто бывает сложнее, и бывает много случаев, когда легальное программное обеспечение использует приемы, напоминающие атаку JIT-компиляция в браузерах один из хороших примеров. Кроме того, злоумышленник может хранить полезную нагрузку в других областях памяти, за пределами стека или кучи, поэтому полезно распознавание хорошего и плохого кода.

В этом посте поговорим об эмуляторе Bitdefender Shellcode Emulator, или, для краткости, bdshemu. Это библиотека, способная эмулировать базовые инструкции x86, наблюдая при этом похожее на шелл-код поведение. Легальный код например JIT-код будет выглядеть иначе, чем традиционный шелл-код, bdshemu пытается определить, ведёт ли себя код в эмуляции, как шелл-код.

Обзор bdshemu


bdshemu библиотека на C, частью проекта bddisasm (и, конечно же, она использует bddisasm для расшифровки инструкций). Библиотека bdshemu создана только для эмуляции кода x86, поэтому не имеет поддержки вызовов API. На самом деле, среда эмуляции сильно ограничена и урезана, доступны только две области памяти:

  1. Содержащие эмулируемый код страницы.
  2. Стек.

Обе эти области виртуализированы, то есть на самом деле являются копиями эмулируемой фактической памяти, поэтому внесенные в них изменения не влияют на фактическое состояние системы. Любой доступ эмулируемого кода за пределы этих областей (которые мы будем называть шелл-кодом и стеком соответственно), спровоцирует немедленное завершение эмуляции. Например, вызов API автоматически вызовет ветку вне области шелл-кода, тем самым прекратив эмуляцию. Однако в bdshemu всё, что нас волнует это поведение кода на уровне инструкций, которого достаточно, чтобы понять, вредоносен код или нет.

Хотя bdshemu предоставляет основную инфраструктуру для обнаружения шелл-кодов внутри гостевой операционной системы, стоит отметить, что это не единственный способ, которым HVMI определяет, что выполнение определённой страницы является вредоносным. Используются ещё два важных индикатора:

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

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

Архитектура bdshemu


bdshemu создаётся как отдельная библиотека C и зависит только от bddisasm. Работать с bdshemu довольно просто, поскольку у этих двух библиотек имеется общий API:

SHEMU_STATUSShemuEmulate(    SHEMU_CONTEXT *Context    );

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

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

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

  1. Входные регистры, такие как сегменты, регистры общего назначения, регистры MMX и SSE; их можно оставить в значении 0, если они неизвестны или не актуальны.
  2. Входной код, то есть код для эмуляции.
  3. Входной стек, который может содержать фактическое содержимое стека, или может быть оставлен со значением 0.
  4. Информация о среде, например режим (32 или 64 бита) или кольцо (0, 1, 2 или 3).
  5. Параметры управления: минимальная длина строки стека, минимальная длина цепочки NOP или максимальное количество инструкций, которые должны быть эмулированы.

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

bdshemu построен как быстрый и простой эмулятор инструкций x86. Поскольку он работает только с самим шелл-кодом и небольшим виртуальным стеком, ему не нужно имитировать какие-то архитектурные особенности прерывания или исключения, таблицы дескрипторов, таблицы страниц. Кроме того, поскольку мы имеем дело только с шелл-кодом и стековой памятью, bdshemu не выполняет проверку доступа к памяти потому, что не разрешает доступ даже к другим адресам. Единственное состояние, кроме регистров, к которому можно получить доступ, это сам шелл-код и стек, и они оба копии фактического содержимого памяти. То есть состояние системы никогда не изменяется во время эмуляции, изменяется только предоставленный SHEMU_CONTEXT. Это делает bdshemu чрезвычайно быстрым, простым и позволяет сосредоточиться на его основной цели: обнаружении шелл-кода.

Что касается поддержки инструкций, bdshemu поддерживает все основные инструкции x86, такие как ветвления, арифметика, логика, сдвиг, манипуляции с битами, умножение и деление, доступ к стеку и инструкции передачи данных. Кроме того, он также поддерживает другие инструкции, например, некоторые базовые инструкции MMX или AVX. Два хороших примера PUNPCKLBW и VPBROADCAST.

Методы обнаружения bdshemu


Есть несколько индикаторов, которые использует bdshemu. Чтобы определить, ведёт ли себя эмулируемый фрагмент кода как шелл-код.

NOP Sled


Это классическое представление шелл-кода; поскольку точка его входа при выполнении может быть неизвестна точно, злоумышленники обычно добавляют длинную последовательность инструкций NOP, закодированную 0x90. Параметры длины последовательностей NOP можно контролировать при вызове эмулятора через контекстное поле NopThreshold. Значение SHEMU_DEFAULT_NOP_THRESHOLD по умолчанию равно 75. Это означает, что минимум 75 % всех эмулируемых инструкций должны быть инструкциями NOP.

RIP Load


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

  1. CALL $ + 5/POP ebp выполнение этих двух инструкций приведёт к тому, что значение указателя инструкции сохранится в регистре ebp; затем можно получить доступ к данным внутри шелл-кода, используя смещения относительно значения ebp
  2. FNOP/FNSTENV [esp-0xc]/POP edi первая инструкция это любая инструкция FPU (не обязательно FNOP), а вторая инструкция FNSTENV сохраняет среду FPU в стеке; третья инструкция получит указатель инструкции FPU из esp-0xc, который является частью среды FPU и содержит адрес последнего выполненного FPU в нашем случае FNOP. С этого момента для доступа к данным шелл-кода можно использовать адресацию относительно edi
  3. Внутренне bdshemu отслеживает все экземпляры указателя инструкции, сохранённые в стеке. Последующая загрузка указателя инструкции из стека каким-либо образом приведёт к срабатыванию этого обнаружения. Благодаря тому, что bdshemu отслеживает сохранённые указатели инструкций, не имеет значения, когда, где и как шелл-код пытается загрузить регистр RIP и использовать его: bdshemu всегда будет запускать обнаружение.

В 64-битном режиме относительная адресация RIP может использоваться напрямую: это позволяет кодировка инструкций. Однако, как ни странно, большое количество шелл-кода по-прежнему использует классический метод получения указателя инструкций (обычно технику CALL/POP), но, вероятно, указывает на то, что 32-битные шелл-коды были перенесены на 64-битные с минимальными изменениями.

Запись шелл-кода самим шелл-кодом


Чаще всего шелл-код закодирован или зашифрован, чтобы избежать некоторых плохих символов (например 0x00, который должен напоминать строку, может сломать эксплойт), или чтобы избежать обнаружения технологиями безопасности например, AV-сканерами. Это означает, что во время выполнения шелл-код должен декодировать себя обычно на месте изменяя свое собственное содержимое, а затем выполняя текстовый код. Типичные методы декодирования включают алгоритмы дешифрования на основе XOR или ADD.

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

Доступ к TIB


После того как шелл-код получил возможность выполнения, ему необходимо найти несколько функций внутри разных модулей, чтобы позаботиться о полезной нагрузке (например, загрузке файла или создании процесса). В Windows наиболее распространенный способ сделать это разобрать структуры загрузчика пользовательского режима, чтобы найти адреса, по которым загружены требуемые модули, а затем найти необходимые функции внутри этих модулей. Ниже дана последовательность структур, к которым будет обращаться шелл-код:

  1. Блок среды потока (TEB), который расположен в fs: [0] (32-битный поток) или gs: [0] (64-битный поток).
  2. Блок среды процесса (PEB), который расположен по адресу TEB + 0x30 (32 бит) или TEB + 0x60 (64 бит).
  3. Информация о загрузчике (PEB_LDR_DATA), расположенная внутри PEB.


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

При каждом обращении к памяти bdshemu увидит, пытается ли предполагаемый шелл-код получить доступ к полю PEB внутри TEB. bdshemu отслеживает обращения к памяти, даже если они выполняются без классических префиксов сегментов fs/gs до тех пор, пока идентифицирован доступ к полю PEB внутри TEB, будет срабатывать обнаружение доступа к TIB.

Направленный вызов SYSCALL


Легитимный код будет полагаться на несколько библиотек для вызова служб операционной системы например для создания процесса в Windows обычный код будет вызывать одну из функций CreateProcess. Легитимный код редко вызывает SYSCALL напрямую, поскольку интерфейс SYSCALL со временем может измениться. По этой причине bdshemu запускает обнаружение SYSCALL всякий раз, когда обнаруживает, что предполагаемый шелл-код напрямую вызывает системную службу с помощью инструкций SYSCALL, SYSENTER или INT.

Строки стека


Другой распространённый способ маскировки содержимого шелл-кода динамическое построение строк в стеке. Это может устранить необходимость в написании независимого от позиции кода (PIC), поскольку шелл-код будет динамически строить нужные строки в стеке, вместо того, чтобы ссылаться на них внутри шелл-кода как на обычные данные. Типичные способы сделать это сохранить содержимое строки в стеке, а затем ссылаться на строку с помощью указателя стека:

push 0x6578652Epush 0x636C6163

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

Для каждого сохранённого в стеке значения, напоминающего строку, bdshemu отслеживает общую длину созданной в стеке строки. Как только порог, указанный полем StrLength внутри контекста, будет превышен, будет запущено обнаружение строки стека. Значение по умолчанию для этого поля SHEMU_DEFAULT_STR_THRESHOLD равно 8. Это означает, что динамическое построение строки длиной не менее 8 символов в стеке вызовет это обнаружение.

Методы обнаружения для шелл-кода режима ядра


Хотя вышеупомянутые методы общие и могут применяться к любому шелл-коду, в любой операционной системе, как в 32-, так и в 64-битной версии (за исключением обнаружения доступа к TIB, которое специфично для Windows) bdshemu может определять специфичное для ядра поведение шелл-кода.

Доступ KPCR


Область управления процессором ядра (KPCR) это структура для каждого процессора в системах Windows, которая содержит много критически важной для ядра информации, но также может быть полезной для злоумышленника. Обычно шелл-код может ссылаться на текущий выполняющийся поток, который можно получить, обратившись к структуре KPCR, со смещением 0x124 в 32-битных системах и 0x188 в 64-битных системах. Так же, как и в методе обнаружения доступа к TIB, bdshemu отслеживает обращения к памяти, и когда эмулируемый код считывает текущий поток из KPCR, он запускает обнаружение доступа к KPCR.

Выполнение SWAPGS


SWAPGS это системная инструкция, которая выполняется только при переходе из пользовательского режима в режим ядра, и наоборот. Иногда, из-за специфики определенных эксплойтов ядра злоумышленнику в конечном счёте нужно выполнить SWAPGS например, полезная нагрузка ядра EternalBlues, как известно, перехватывает обработчик SYSCALL, поэтому нужно выполнить SWAPGS, когда состоялся SYSCALL, подобно тому, как это сделал бы обычный системный вызов.

bdshemu запускает обнаружение SWAPGS всякий раз, когда инструкция SWAPGS выполняется подозрительным шелл-кодом.

Чтение и запись MSR


Иногда шелл-код (например вышеупомянутая полезная нагрузка ядра EternalBlue) должен изменить обработчик SYSCALL, чтобы перейти в стабильную среду выполнения (например, потому что исходный шелл-код выполняется в высоких значениях диапазона IRQL, которые необходимо снизить перед вызовом полезных подпрограмм). Это делается путём изменения MSR SYSCALL с помощью инструкции WRMSR, а затем ожидания выполнения системного вызова (который находится на более низком уровне IRQL) для продолжения выполнения (здесь также пригодится метод SWAPGS потому, что на 64-битной версии SWAPGS должна выполняться после каждого SYSCALL).

Кроме того, чтобы найти образ ядра в памяти и, следовательно, полезные процедуры ядра, быстрый и простой способ запросить SYSCALL MSR (которая обычно указывает на обработчик SYSCALL внутри образа ядра), а затем пройти по страницам назад, пока не будет найдено начало образа ядра.

bdshemu будет запускает обнаружение доступа MSR всякий раз, когда подозрительный шелл-код обращается к MSR SYSCALL, (как в 32-, так и в 64-битном режиме).

Пример


Проект bdshemu содержит несколько синтетических тестовых примеров, но лучший способ продемонстрировать его функциональность использовать реальный шелл-код. В этом отношении Metasploit замечателен в создании разных видов полезной нагрузки с использованием всех видов кодировщиков. В качестве чисто дидактического [прим. перев. назидательного] примера возьмём такой код:

DA C8 D9 74 24 F4 5F 8D 7F 4A 89 FD 81 ED FE FFFF FF B9 61 00 00 00 8B 75 00 C1 E6 10 C1 EE 10 83 C5 02 FF 37 5A C1 E2 10 C1 EA 10 89 D3 09 F3 21 F2 F7 D2 21 DA 66 52 66 8F 07 6A 02 03 3C 24 5B 49 85 C9 0F 85 CD FF FF FF 1C B3 E0 5B 62 5B 62 5B 02 D2 E7 E3 27 87 AC D7 9C 5C CE 50 45 02 51 89 23 A1 2C 16 66 30 57 CF FB F3 9A 8F 98 A3 B8 62 77 6F 76 A8 94 5A C6 0D 4D 5F 5D D4 17 E8 9C A4 8D DC 6E 94 6F 45 3E CE 67 EE 66 3D ED 74 F5 97 CF DE 44 EA CF EB 19 DA E6 76 27 B9 2A B8 ED 80 0D F5 FB F6 86 0E BD 73 99 06 7D 5E F6 06 D2 07 01 61 8A 6D C1 E6 99 FA 98 29 13 2D 98 2C 48 A5 0C 81 28 DA 73 BB 2A E1 7B 1E 9B 41 C4 1B 4F 09 A4 84 F9 EE F8 63 7D D1 7D D1 7D 81 15 B0 9E DF 19 20 CC 9B 3C 2E 9E 78 F6 DE 63 63 FE 9C 2B A0 2D DC 27 5C DC BC A9 B9 12 FE 01 8C 6E E6 6E B5 91 60 F2 01 9E 62 B0 07 C8 62 C8 8C

Сохранение этого кода как двоичного файла как shellcode.bin с последующим просмотром его содержимого дает плотно упакованный фрагмент кода, весьма характерный для зашифрованного шелл-кода:



В disasmtool инструменте проекта bddisasm, для запуска эмулятора шелл-кода на входе можно воспользоваться параметром -shemu.

disasmtool -b32 -shemu -f shellcode.bin

Выполнение отобразит пошаговую информацию о каждой эмулируемой команде, но так как эта трассировка длинная, давайте перейдем непосредственно к концу if:

Emulating: 0x0000000000200053 XOR       eax, eax        RAX = 0x0000000000000000 RCX = 0x0000000000000000 RDX = 0x000000000000ee00 RBX = 0x0000000000000002        RSP = 0x0000000000100fd4 RBP = 0x0000000000100fd4 RSI = 0x0000000000008cc8 RDI = 0x000000000020010c        R8  = 0x0000000000000000 R9  = 0x0000000000000000 R10 = 0x0000000000000000 R11 = 0x0000000000000000        R12 = 0x0000000000000000 R13 = 0x0000000000000000 R14 = 0x0000000000000000 R15 = 0x0000000000000000        RIP = 0x0000000000200055 RFLAGS = 0x0000000000000246Emulating: 0x0000000000200055 MOV       edx, dword ptr fs:[eax+0x30]Emulation terminated with status 0x00000001, flags: 0xe, 0 NOPs        SHEMU_FLAG_LOAD_RIP        SHEMU_FLAG_WRITE_SELF        SHEMU_FLAG_TIB_ACCESS

Мы видим, что последняя эмулированная инструкция MOV edx, dword ptr fs: [eax + 0x30] это инструкция доступа к TEB, но она также запускает эмуляцию, которая должна быть остановлена, поскольку это доступ за пределы памяти шелл-кода (вспомним, что bdshemu остановится при первом обращении к памяти вне шелл-кода или стека). Более того, этот небольшой шелл-код (сгенерированный с помощью Metasploit) вызвал 3 обнаружения в bdshemu:

  1. SHEMU_FLAG_LOAD_RIP шелл-код загружает RIP в регистр общего назначения, чтобы определить его позицию в памяти.
  2. SHEMU_FLAG_WRITE_SELF расшифровывает сам себя, а затем выполняет расшифрованные фрагменты.
  3. SHEMU_FLAG_TIB_ACCESS обращается к PEB, чтобы найти важные библиотеки и функции.


Этих срабатываний более чем достаточно, чтобы сделать вывод, что эмулируемый код, без сомнения, является шелл-кодом. Что еще более удивительно в bdshemu, так это то, что обычно в конце эмуляции память содержит расшифрованную форму шелл-кода. disasmtool достаточно хорош, чтобы сохранить память шелл-кода после завершения эмуляции: создаётся новый файл с именем shellcode.bin_decoded.bin, содержащий декодированный шелл-код. Давайте посмотрим на него:



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

Заключение


В этом посте мы представили эмулятор шелл-кода Bitdefender, который является важной частью технологии обнаружения эксплойтов HVMI. bdshemu построен для обнаружения индикаторов шелл-кода на уровне двоичного кода, без необходимости эмулировать сложные вызовы API, сложное расположение памяти или архитектурные объекты, такие как таблицы страниц, таблицы дескрипторов и т. д. bdshemu фокусируется на том, что имеет наибольшее значение, эмулируя инструкции и определяя шелл-код по поведению.

Благодаря своей простоте bdshemu работает с шелл-кодом, нацеленным на любую операционную систему: большинство методов обнаружения определены на уровне поведения инструкций, а не на высокоуровневом поведении (например на уровне вызовов API). Кроме того, он работает как с 32-битным, так и с 64-битным кодом, а также с кодом, специфичным для режимов пользователя или ядра.

Ссылка на Github

На тот случай если вы задумали сменить сферу или повысить свою квалификацию промокод HABR даст вам дополнительные 10 % к скидке указанной на баннере.

image



Рекомендуемые статьи


Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru