Hi, I thought I would do something on the topic of Windows Exploitation. I have done a lot on Linux in the past. Windows is also interesting times, why what write about it.
Buffer overflows on Windows are similar to those on Linux. As an example application we exploit dawn.exe, which I got from the CTF sunset:dawn2 from Vulnhub. This runs on the machine via Wine and is a simple echo server which plays back what you have sent. I run the whole thing in compatibility mode ("Windows 7 & Windows 8) on a Windows 10 VM because I don't have a Windows 7 installation.
Ok, let's see how the application runs
We see the application is running and waiting for incoming connections on port 1985. In the Kali VM the whole thing looks like this, we have established a connection with nc and simply sent "test". We get the input back and in the application itself we see the connection and the message "test".
Let's have a look at the application in Ghidra. I show here only a few salient points of the application but not how to disassemble this 😄 There is no Main method like this, but we can get to the Main method via the "entry" method. In the Main method the server is created and set to Listen. If a connection comes in, it is accepted and the messages are sent back to the sender. The whole thing is realized with a TCP socket, which can be seen in the method call socket(2,1,0).
I have framed the most important points. In the blue frame we see the recv method, which receives the data we send, these are buffered in a buffer, which is 1024 bytes long. Now we come to the crux, which is circled in red. We see here the call to the method copyintobuffer, which I named with Ghidra to get a bit more overview. Here the buffer with our sent data is passed and looking at the method more closely we see where our buffer overflow is triggered.
Here you can see where the problem lies, here a new buffer is created but this time it is only 268 bytes long. By using the strcpy method, the data is copied from one buffer to the other without paying attention to the size differences. Ok, enough rambling now let's get into the nitty gritty.
First of all, let's crash the application!.
Ok, at 300 bytes the application is crashed which is quite good, so we can now create a small pattern with the tool pattern_create from Metasploit to later determine the exact offset to the EIP.
We load the program with the Immunity Debugger and let it run. After that we have to press F9 again to run the program. After that we can send the generated pattern with nc and crash the application.
In the picture above we see that the instruction pointer EIP has been overwritten with the pattern, we can now take the value from the register and determine the exact offset to the instruction pointer with the tool pattern_offset
.
The exact offset to the instruction pointer is 272 bytes, which we can pad with junk data. Now we can start building the basic framework of the exploit. I do the whole thing in Python.
As library I take the pwntools library. The whole thing should look like in the picture. Next we can generate a shellcode with msfvenom, which will be embedded in the exploit.
As payload I take a simple meterpreter reverse TCP payload. I then output the whole thing as Python code to embed it directly into the exploit. I have also thrown out all null bytes. Here at this point you could encode the payload but it should work like this.
The embedded shellcode or the payload in the exploit should look like this. I have expanded the exploit code so that it looks like below.
The payload now consists of junk followed by the EIP value which should overwrite the EIP, a small nop-sled of 32 bytes and the shellcode we created with Msfvenom. At this point we are almost done, the only thing missing is a jump address pointing to our shellcode.
We see here after running the exploit that our stack pointer points to our NopSled. It is very obvious to take the stack address, yet we can't take it, because first of all we have a null byte in the address. Secondly, at runtime, we don't really know the address either, so it makes more sense to look for an address that is static. Why static? Well, quite simply Windows also has ASLR. What exactly is the static address supposed to do? This address should not do anything else than jumping to the address of the stackpointer to execute the shellcode. Good, that the Immunity Debugger has possibilities to search for such addresses. You just have to list all executable modules and pick the Kernel32.dll or ntdll.dll. Why these two? Well that's because they are loaded with every application and therefore always present. In the ntdll.dll you can simply search for the instruction JMP ESP
, which is on an address, which does not contain null bytes.
We can embed this address as an EIP value in the exploit, which completely replaces the pattern BBBB
.
Now, when we run our exploit, we should get a meterpreter session. Here I should mention that Defender should be disabled if necessary. I have here a small recording of how the whole thing is executed at the end 😄
I hope you liked it, and could see that the difference to Linux is relatively small 😄