The previous post explained how to setup the environment so that we would be able to actually debug the crashing process. In this post I will try to explain the process of analyzing it and building a working exploit. So the first step is to identify why it crashed in the first place.
Let’s fire up the exploit again and it should land us right into the olly screen with the INT 3 we hexedited in. We already know what to do with that(replace it with PUSH ESI), let’s continue with the stack and the instruction. First of all let’s document them a little bit(only the parts I found interesting are documented). The comments are on the following line due to space issues.
00401030 81EC 58020000 SUB ESP,258 ; substract size needed for variables 00401036 A0 E0684000 MOV AL,BYTE PTR DS:[4068E0] 0040103B 56 PUSH ESI 0040103C 57 PUSH EDI 0040103D 884424 08 MOV BYTE PTR SS:[ESP+8],AL 00401041 B9 95000000 MOV ECX,95 00401046 33C0 XOR EAX,EAX 00401048 8D7C24 09 LEA EDI,DWORD PTR SS:[ESP+9] 0040104C F3:AB REP STOS DWORD PTR ES:[EDI] ; zero the stack 0040104E 66:AB STOS WORD PTR ES:[EDI] 00401050 8D4C24 08 LEA ECX,DWORD PTR SS:[ESP+8] 00401054 51 PUSH ECX 00401055 68 4C604000 PUSH vuln.0040604C ; ASCII "%.8X" 0040105A AA STOS BYTE PTR ES:[EDI] 0040105B E8 40000000 CALL vuln.004010A0 ; inline printf 00401060 8BBC24 6C020000 MOV EDI,DWORD PTR SS:[ESP+26C] ; address of our payload 00401067 83C9 FF OR ECX,FFFFFFFF 0040106A 33C0 XOR EAX,EAX 0040106C 83C4 08 ADD ESP,8 0040106F F2:AE REPNE SCAS BYTE PTR ES:[EDI] 00401071 F7D1 NOT ECX ; ECX contains size of our payload 00401073 2BF9 SUB EDI,ECX 00401075 8D5424 08 LEA EDX,DWORD PTR SS:[ESP+8] 00401079 8BC1 MOV EAX,ECX 0040107B 8BF7 MOV ESI,EDI 0040107D 8BFA MOV EDI,EDX 0040107F C1E9 02 SHR ECX,2 00401082 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ;copy payload to stack address @ EDI 00401084 8BC8 MOV ECX,EAX 00401086 83E1 03 AND ECX,3 00401089 33C0 XOR EAX,EAX 0040108B F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] 0040108D 5F POP EDI 0040108E 5E POP ESI 0040108F 81C4 58020000 ADD ESP,258 ; set ESP to the RET address 00401095 C3 RETN ; jump to the RET address
What can we see/learn from the above statements? That everything before the printf is irrelevant and almost everything after that is relevant. So what are the next steps? We got the slightly documented asm, we got a general idea of what the function does(also cause we got the source of it) and we know our goal…excute the shellcode.
We will start by taking a look at the stack just before the function starts to copy our payload onto it, cause it’s a huge amount of space on the stack(600bytes see the SUB esp,256) I’ll just show the stack towards the end of it.
w0000t seems like we are starting to understand this…like you can see inside the red squares…the RET address on the stack matches the instruction address AFTER the call to our vulnerable function. So indeed like it’s explained on the forum and in several papers…when you fill up the buffer to much you will overwrite any saves RET addresses on the stack. Hmmm so when we first got our error and the exploit didn’t work it must have ment that the NOPS(0x90) overwrote the RET address, let’s verify that. The next screenshot shows the stack when it’s beeing filled and just before overwriting the RET address.
So the red bracket clearly shows that the RET address is almost overwritten. The dark red(brown w/e moves you) shows that ESI still points to a large amount(exact amount can be seen in ECX which holds the length to be written) of data yet to be written. So we can now confirm that indeed there are to many NOPS. Take a look at how the stack looks like after all data has been written.
The first red dot indicates where the RET address was and the second red dot indicates the end of the data that has been written. So let’s fix it that the RET address get’s overwritten correctly(in my case diminish the nops and adjust the place where the return address is written into the buffer).
Like you can see on the above screenshot we now control the RET address correctly except that it’s horribly wrong and the application still crashes. So how do we fix this? By using a tool called findjmp || findjmp2 this tool is able to search for us in the provided dll for a correct address to use. If you want to know what dll to use, just look it up in olly. Press ALT+E which should open a window displaying the currently loaded modules. KD was working with ntdll.dll so I just followed his lead(hint:try to use modules which are always loaded by the process…so that you have a more reliable exploit).
findjmp.exe ntdll.dll esp
Scanning ntdll.dll for code useable with the esp register
0x7C914663 call esp
0x7C919DB0 push esp – ret
0x7C95311B call esp
I used the first address, 0x7c914663. If you did it all correct your olly should now look like this:
Like you prolly already noticed…we are inside NTDLL.DLL now at the CALL ESP instruction that we looked up earlier using findjmp(don’t forget to use F7 in olly instead of F8 when it hits the function RET instruction). Now press F7(step into) again and it should land you right inside the mini shellcode.
If you execute the mini shellcode, you will notice that it still will not land you inside the main NOP sled, instead it will crash. Take a look at the following screenshot to understand why.
The red arrows show the current situation, the green arrows show how it should be. Like you can see on XP SP3 it’s not ECX which points to the main NOP sled but it’s EDX. Let’s do that press the spacebar in olly and change JMP ECX to JMP EDX, make sure to write down the changed opcode cause you need to adjust that one in the source. Now if you press F7 on the changed jmp it will land you right into the main NOP sled!! The opcodes inside the red circle math the opcodes of the shellcode in the source.
Voila there you go a fixed exploit. Like the original author says in his forum post the shellcode won’t prolly work(certainly didn’t in my case) because some hardcoded addresses need to be fixed. This is a minor issues since now we understand how to debug the process we want to exploit. You can run into some difficulties when replacing shellcodes because of restricted characters for example.
Hope this last part answered a lot of questions and made the process of writing a exploit a little bit more understandable. In the future I might write about the process of selecting the correct shellcode and how to avoid bad chars. For the moment beeing this is all folks.