Today I’m going to share with you the hard time I was having creating a working exploit for “KnFTP Server”, please read the full post as there are many interesting things inside and they might come in handy for you someday !
Vulnerable software : “KnFTP Server 1.0.0” ( https://www.exploit-db.com/apps/182e4b13190ed23c06c8647dda9198dd-knftpd-1.0.0-bin.zip )
Crash POC : https://www.exploit-db.com/exploits/17856/
- Fuzzing :
Since we already have the crash POC we won’t dive deep into “how-to fuzzing”. Looking at the crash POC we see that the vulnerable command is “PWD” :
Just to confirm that we have control over the SEH handler we replicate the crash, I hooked up the process to immunity debugger then lunched the script and here is what I got :
Great ! so now we have to determine the right amount of data to send in order to overwrite SEH. For this I used “pattern_create.rb” and “pattern_offset.rb” from Metasploit.
First, I created a 9000 long pattern :
Then I replaced the “\x41″*9000 with it :
So now the script should send that pattern we created and once the application crash we get pull out the exact bytes that overwrote SEH and pass it to “pattern_offset.rb” in order to tell their location :
Ok, we now know that SEH is overwritten after 324 bytes of data. We can confirm that by sending 324 bytes of data followed by 4 B’s and we should overwrite SEH with “42424242” … let’s see :
Awesome ! now we confirmed that we own SEH. Now we can jump to the exploitation part.
- Exploitation :
Since we have control over SEH handler the typical thing to do is :
- Search for an address that would point to a “pop pop ret” commands.
- Generate a shellcode ( and eliminate any bad characters from it ).
- Control the next SEH handler and replace it with a jump command.
- Fill in some nops ( for reliability ).
- The exploit would look something like : junk -> jmp_seh -> seh -> shellcode.
But not for this case AT ALL and let me tell why …
* Null character in the “pop pop ret” address :
I used the great “mona.py” script to search for a POP POP RET sequence and the output was :
Can you see the issue ? well .. yes null byte in the beginning of the addresses.
Since we can’t use a null byte in a regular exploit ( because a null byte would stop the execution of all the commands that comes after it ). We have to adopt another approach which is place everything before that address in our exploit, meaning :
junk -> shellcode -> jmp_back_to_shellcode -> seh
Using this method we can still have a null byte in our “pop pop ret” address because if for example take “0x004011CB”, the address will have to be inputted inverted ( little indian ) format : “\xCB\x11\x40\x00” so the last byte in our exploit is “\x00” and there is nothing coming after it. In fact there is no need to put the last “\x00” byte because the application will fill it automatically as it’s the end of the user input.
Let’s test this out ( shellcode = “44”*10 … just to test things out first ) :
Cool, we are now pointing to the right “POP POP RET” address and it’s taking us back to our controlled area.
We need to put things together now and see how it works, put in mind that we have about 300 bytes space for our shellcode.
Remember our exploit should look something like : junk -> shellcode -> jmp_back_to_shellcode -> seh ..
SEH is overwritten after 324 bytes, meaning that we need to subtract the size of ( junk + shellcode + jmp_back_to_shellcode ) from it. So we’ll now proceed with adding all other components to our exploit in order to have an accurate calculation.
In order to create the opcode for the jump I used the “nasm_shell.rb” script :
We’ll leave our shellcode at last so we’ll fill it’s place with A’s, now that we have everything we need we can do calculations.
We need to pass 324 bytes of data at first the 3 bytes that follow it will overwrite the SEH handler, and the jump will occupy 2 bytes => so our exploit “for now” will look like this :
Let’s test it out :
Press F8 to take the jump !
But !!! since we filled in 322 bytes of A’s and we are jumping 100 bytes ( backwards ) it means we should jump to A’s not this !!
I soon came to the realization that this is messed up and I have to work with the 28 bytes and make something … an egghunter comes to mind but it’ll need at least 32 bytes ..
I was messing around and thought of making use of the small chunks of data I have control over with the combination of that 28 bytes ( locate them using a pattern and use jumps to hop from chunk to another and execute the shellcode ) but really we don’t have much space ! the only 3 chunks I found were like 4 bytes so it doesn’t really help.
* Tight space :
Until I had a moment of glory when I found out ( using mona.py ) that the rest of the chunk is located in a different address :
Still not much space but something to work with, what I need to do is the following :
- Send a shellcode to the application before crashing it using some other commands like “CWD”
- Since the shellcode now reside in memory I can point the execution flow to that space I found and place an egghunter there to search for the shellcode and execute it.
But first I need to make sure I had control over that area, I used the 32 bytes of the “BEAUTIFUL” egghunter code inside the junk data and see if I can have it there ( if not then create a pattern, get the lower and the higher addresses of that chunk of data and locate it **EXTRA WORK** )
CONFIRMED ! egghunter is there, but the last thing we need to do is place it somewhere in the middle of those 322 bytes because we see that if we place it at the end then it’s going to corrupt the execution flow as the “pop pop ret” is going to point directly to the last byte of the egghunter which is “JMP EDI”.
WAIT WAIT !!!
At some point we’ll need to jump to that chunk of data, replace those A’s with a nop slide and the egghunter will be executed, but we see that if we need to jump to that chunk then we’re going to have to use addresses that begin with a null byte …. OH NOT AGAIN !!
* Null character .. again : ( Creativity )
Now we have to overcome the null byte issue again, how are we going to jump to an address that begins with a null byte inside exploit. We already clarified that we can’t have any null byte inside our exploit as it’s going to terminate the execution flow.
With little thinking I came up with an idea, if I can put some commands that are going to generate the address for me ( those commands will not use null bytes ) and place it in a register then jmp to it … POSSIBLE !!
The 28 bytes of space are going to come REALLY REALLY handy as we’re going to use them in order to generate the address that begins with a null byte.
For that we’ll have to do some assembly calculations, what instructions and values we can use in order to generate a value of “003E3988” !!
We’ll use the EAX register to store the value and “JMP EAX” in order to jump to our egghunter …
After some calculations I’ve came up with the following commands that are going to generate “003E3988” in EAX for us :
AND EAX,41414141 “ZERO OUT EAX”
AND EAX,3E3E3E3E “ZERO OUT EAX”
SUB EAX,4A3B5468 “=> EAX=003E3988”
I have generated the opcode for those commands and the final code is : “\x25\x41\x41\x41\x41\x25\x3E\x3E\x3E\x3E\x2D\x7D\x68\x4A\x4B\x2D\x51\x09\x3C\x6A\x2D\x68\x54\x3B\x4A” and it’s 25 bytes long .. so close .. so close …
Where to put it ? remember that placing something at the end of our junk data will automatically be at the 28 bytes space ? this is going to be there so we’ll append this code at the end.
We now only need to use that jmp in order to place ourselves at the beginning of the generator ( jump back 28 bytes “\xEB\xE2” ) and place a “JMP EAX” ( \xFF\xE0 ) at the end of that since we have extra LAST 5 bytes.
YAAAAY !!! we got a reliable execution flow and it’s now pointing to that chunk of data and you can see the egghunter there just sitting waiting to be executed :)
* Putting it all together :
- We have to replace the A’s with nops inside our exploit because we are hitting A’s too much and they could interrupt the execution flow, in the other side if we hit nops slide then we are 100% sure that the next instruction after then will be executed.
- I have tested our characters and we don’t have any limitations on the “CWD” command only “x00 and xFF”.
- We don’t have any shellcode size restriction now as we are injecting it from a different dedicated input.
I have added a bind meterpreter shellcode on port 4444, lunched the exploit and started the multi_handler aaaaand … :
VOILA ! this is what I wanted to share with you and I hope it’ll help you overcome the issues I was having when creating this exploit.
Exploit code is available at : https://github.com/MrNasro/scripts/blob/master/KnFTP_1.0.0_exploit.py