EternalBlue Series Part 3: Reverse engineering
by h3xduck
2 July 20211. Initial reverse-engineering of the vulnerable code.
As the description of the metasploit module indicated, there is some sort of buffer overflow somewhere in the memory address pointed by Srv!SrvOs2FeaToNt. Our task is to find where exactly and understand why it happens.
Now, there are two main ways to do this:
- (Hard) Either we debug the windows kernel, looking for the instruction in a live system or
- (Easy) We download an offline copy of the vulnerable program and decompile it.
If you are familiar with debuggers, you will probably recognize that the first option requires a complicated setup: since we are debugging a process in the kernel and not just a program we will need a second machine connected to the one being debugged, otherwise since the whole OS is frozen while putting breakpoints in the kernel then our debugging program will be frozen too.
Apart from this, debuggers in Windows require to download the so-called “symbols”, which are labels of functions, global variables, line numbers… and which allow us to work in our debugger with human-readable addresses, otherwise we would be lost trying to identify what each memory address means. The configuration of these symbols for old systems like XP require a painful manual process which I’m not mentioning here just because for this task I’m giving you an alternative faster way of doing it with Ghidra. Still, if you are interested in debugging your kernel, this is a good starting point on how to setup a two-machine debugging setup as I mentioned you will need.
Once you have your machines connected, you will find yourself with a setup like the following:
And taking into account this windbg command reference you will be able to search for the function with interests us:
u Srv!SrvOs2FeaListSizeToNt
The guided process
Having mentioned the alternative process you can follow by your own, let’s now follow the “easy” path and see how it’s done step by step. Remember, we are going to reverse engineer a windows program and localize the vulnerable code. But which program exactly? Well, the metasploit module did not tell us, but provided that we know that the code is on the functions pointed by the symbol Srv!SrvOs2FeaToNt and srvnet!SrvNetWskReceiveComplete, then a quick google search tells us that this corresponds to the kernel drivers srv.sys and srvnet.sys. I personally found this page useful for downloading them.
After you have downloaded the programs, launch Ghidra and load srv.sys. Most probably you will be warned that you need to download the windows symbols before any operation. Here you can find a nice guide on how to do it.
Although the process is quite straight forward, if you have problems with the download you may get the PBS files manually from google instead of using Microsoft’s server.
Once you have all set we start the automatic analysis of Ghidra, which will decompile the drivers and put the symbols (which were downloaded in the previous step) where they correspond. After the decompilation, we search for the function we said we were looking for:
The results seem to be quite promising, so we will go inspect memory address 0x0002f4a8 by using Ghidra’s navigation tool. We get the assembly instructions, and also a decompilation of the function SrvOs2FeaListSizeToNt too!
Now, at line 27 we can find an interesting operation. What we have is a variable “param1” (not the original variable name, it’s a decompilation) which is being casted from an integer (dword) pointer to a short (word). Then in that word the subtraction of itself with another variable piVar1 is stored. Thus we are essentially casting into a short the result of the subtraction of two integers.
But why would this even be a bug which derives into a serious vulnerability? Well, the problem is that we are discarding half of the dword because of this casting, and therefore we are losing the 16 highest bits encoded in (piVar1-param_1). And this is a huge problem once we realise what is actually encoded in these variables. Also, note that we store in param_1 the (short) value of the subtraction, but in fact param_1 keeps being a dword (int), it’s just that it’s highest 16 bits have not been overwritten.
Now, before going with the full explanation of what is going on here and seeing an example on how this code is such a big vulnerability, we need to study some concepts of SMB which we will need to fully understand the code.
See you on the next part!
tags: stack - overflow - buffer - exploitation - shellcode - RCE - eternalblue - vulnerability - windows - eternalblue - ghidraThis work is licensed under a Creative Commons Attribution 4.0 International License.