In this blog, we will be hacking into an FTP server using a manual Buffer Overflow attack. We will be crafting our own exploit payload as we move forward. Lab setup consists of Windows 7 as host OS and Kali Linux as an attacker machine. The version of FTP we are using is Easy File Sharing Web Server 7.2.
Host IP: 192.168.116.136
Attacker IP: 192.168.116.135
Set up a Windows 7 32 bit Host machine and install Simple File Sharing Web Server and Immunity Debugger. Run the File Sharing Web Server and Immunity debugger as administrator. Then load the running fsws process into the immunity debugger.
The first step is to find the parameters in the web app vulnerable to a buffer overflow. So let's send an HTTP request to the webserver with a payload of 4200 bytes in the GET request. You can opt for a bigger payload if the program does not crash.
We are using the above Python script to send our payload to the server.
Let's also have a look at the immunity debugger as we send the payload.
Here we see our first access violation. In the EDI register, we can see that there is a SQL table in the background and the instruction is making a query to the database. The file name can be as long as we want. Let’s see how we can exploit this to get remote code execution on the webserver.
From the above image, we can see that the webserver crashed and the EIP (Instruction Pointer) is overwritten with the As from our payload (\x41=A).
Let's also have a look at the rest of the overwritten buffer. If the rest of the buffer is loaded intact into the memory we can overwrite EIP with an instruction to redirect the execution flow to the memory section where our shellcode resides. Before we move to shellcode - we should check for bad characters. For this, we will follow the same process of loading all possible hex characters into our payload and execute it. Then we will check the memory for missing characters or broken sequences and then take care to avoid such characters in our shellcode to be executed.
Here I found the bad characters to be - \x00,\x0a,\x0d,\x0c
Out of which \x00 - null byte \x0a - Line feed \x0d - carriage return are the most common bad characters.
Now let's have a look at the buffer we overwritten in the step above.
Here we can see that our payload is overwriting the Structured Exception Handler.
So, What exactly is an SEH?
SEH can be described as a list of functions that tries to solve an upcoming exception. Here the function will try to solve the exception by one handler after another until the exception is solved or there is no handler left and the program will crash.
Here we want the program to handle this exception. From the image above we can see that we have overwritten the SE handler and also the pointer to the next SE handler. To control the SE handler we need to find the exact offset that is overwritten by the payload in the buffer on the SE handler.
Locating SEH and nSEH
To do that we can create a unique pattern of strings using the Metasploit module and then query the contents of the SE handler to the same module to find the location of exact overwrite.
After doing the same we find the offset to be at 4065 bytes as shown in the image.
To exploit a buffer overflow in such a situation we will use the technique of pop-pop-ret. In this technique, the first SEH handler must point to a pop-pop-ret instruction. Here return will make sure that the execution comes back to the address just before the SEH handler. To do this we pop the top 2 values of the stack and return to the next value (pop - pop - ret).
So whatever we write here will be considered as assembly language and we will put an instruction for a short jump in here that will skip the exception handler and start executing our shellcode we inject in the buffer.
Here we can start writing our shellcode 6 - 10 characters ahead of SEH handler and instruct the pointer to next SEH record to jump onto our shellcode.
So now let's find out the next location of the SEH handler using mona pattern_offset.
Here we are overwriting the next SEH after 4065 bytes and nSEH will be at 4061 bytes.
Let’s now find out all the modules that come with the application so that we can use a pop - pop -ret instruction already present in the application by just giving the nSEH location of this instruction.
To do this we enter the command ‘ !mona seh ‘ in the immunity debugger.
Then open the seh.txt file in the Windows OS. Here we will search for instruction -
Pop esi - pop edi - ret
And then copy the address of the same and replace it with the code that will be executed on SEH.
Before copying this address make sure that the ASLR and SAFE SEH bits are set to false and it is not an instruction from the OS library.
So our payload is now updated with more information.
Let's set up a breakpoint on the above address in the immunity debugger to see the execution in action.
Once the RETN inst executed we will reach our JMP SHORT instruction.
Now it’s time to replace our nops with a working payload to get code execution for the shell. After injecting my shellcode in this nops area and trying to get it executed - due to some reason only a first few bytes would get executed and the payload would then fail.
Here we can use an ‘ Egg Hunter ‘ payload. The egg hunter is composed of a set of programmatic instructions that are translated to opcode and in that respect, it is no different than any other shellcode. The purpose of this shellcode is to search the entire memory range for our final stage shellcode and redirect execution flow to it.
To do that we have another parameter here where we can inject our payload - that is the User-Agent. When we write an egg hunter it will be a 4-byte string. If by default if we use mona it will be “w00t”.
We will put this in front of our payload so that it understands that our shellcode to be executed lies ahead and pass the execution to it. We will write it twice so that the egg hunter does not find itself in the memory (hunter is 1 time w00t and egg is 2 times).
Let’s use the egg hunter from the file provided with mona.
Now our payload is
For payload 2 we will just create a TCP reverse shellcode that will give us code execution and inject it in the ‘ User-Agent ’. Link to the code for reference is provided in the references. Let’s now see this in action again.
Here the egghunter searches for the occurrence of strings w00t twice in the memory recursively. Now let’s set a breakpoint at SCAS DWORD PTR ES:[EDI] as shown below to pause execution once it finds an occurrence of ‘ w00t ‘ string.
We see that the hunter seems to have found itself or a random occurrence of the string in the memory but it will recurse again to find the string again in the same order. Now set the breakpoint at JMP EDI - as EDI will be the location of our payload and let the execution continue.
Here we see that the egg hunter has found our egg and the payload that precedes the egg. Now set up a handler on the attacking machine to receive the shell once our payload executes and let the execution continue.
Here we can see that the execution has jumped to our payload and we have a shell on our target system.