Mouse Server
Technical analysis of Mouse Server exploit
Last updated
Technical analysis of Mouse Server exploit
Last updated
OS : Windows
Version : Latest
Vulnerability : By-design remote code execution on MouseServer servers.
Pre-Requisites to follow along : Basic knowledge on assembly, IDA & WinDbg
Impact : Code Execution as Administrator
Lets begin by performing static analysis of MouseServer first. Upon installing mouse server on our windows VM, we analysis running ports via tcpdump
utility.
Output shows that MouseServer.exe
is listening on port 1978
on our VM. Lets use telnet to connect to this port. Telnet shows that string "system windows 6.2" is printed once you connect to the port which implies that before sending data over the socket, we need to first fetch this string and post that send our payload. Given that, lets start by sending some random data to this port and analyse the input flow.
We attach WinDbg
to the process and set a breakpoint at ws2_32!recv
. The reason we choose this WinAPI is because it is the most commonly used API for receiving data over TCP socket. This implies that if input is received over TCP, then this API will get triggered and upon finishing the call to recv
we will land directly into code which performs analysis over our input buffer.
Let's verify this hypothesis.
Open Windbg as Administrator and attach itself to MouseServer.exe . Using narly to view the properties of executable shows that MouseServer is compiled with DEP and SafeSEH but is not compiled with ASLR. This is common mistake where developers often forgets to build the executable with ASLR.
Alright, enough chat, lets set a breakpoint. We will be using the following script to send data to MouseServer
Executing the above code triggers the breakpoint in Windbg
Lets return from this function and we will find the address we step right into.
Notice that eax
contains 0x64
which is the length of input buffer. Lets take note of this address 0040A7D0
and open it in IDA. Look at Windbg the base address of MouseServer.exe is at 0x400000
and since there is no ASLR base address remains constant across several execution.
eax
is compared against -1 which likely checks if recv call is successful. Stepping through windbg we reach a function call at 0x40a7F4
. Looking at the arguments shows that some values + our input buffer is passed into it.
Educated guess suggests that there is some sort of structure being used by developer which looks something like this :-
Keeping this in mind, lets look into function sub_40ABD0
in IDA.
As shown, edi
points to argument i.e the input structure. [edi+4]
is input_size which implies that size of input should be greater than/ equal to 3.
Now, [edi+9]
is loaded into esi
which directly points to our input buffer. Next few instruction suggests that if first 3 chracters are either key
or mos
function sub_40D9C0
is called or else sub_40BF30
is called. Also note that at address 0x40ac0f
strstr
function is called which basically makes sure that the last character is \n
.
Therefore new input will now be couple of As followed by \n
.
Analysing function sub_40Bf30
shows that there are multiple comparisions being made against input buffer. Extensive search for the right branch leads us to multiple interesting comparisons i.e openfile
,browser openurl
and utf8
. Lets analyse each of each branch to prepare the exploit chain.
At address 0040CEC9
input is compared against "browser openurl " string. Following down the rabbit hole we notice that eventually ShellExecuteA
is called.
Lets send input as browser openurl http://google.com
to the server with breakpoint at 40cec9.
Following the input in windbg shows that eventually ShellExecuteA(0,open,"http://google.com",0,0,3)
is called. Continuing the execution reveals that http://google.com
is opened in browser. We now have a way to make target download our payload.
At address 0040D61F
input is compared against "openfile " string. Following down the rabbit hole we notice that eventually move to 0040D6A0
address
Lets send our input as "openfile C:\\Windows\\System32\\cmd.exe\n" to server with breakpoint at 40d627
Following the input in windbg shows that eventually C:\\Windows\\System32\\cmd.exe
is passed to function sub_4044d0
at 40d6be
. Continuing the execution reveals that indeed cmd.exe
is executed on target. We now have a way to execute payloads on target.
Final Exploit :-
We have already discussed about OpenFile, lets discuss about utf8
comparision.
At address 040C388
comparision is made against 5 bytes of input with "utf8 ". Upon successful comparision it goes down straight into 040C3A2
i.e function sub_40F030
.
Notice that ecx
has been made point to [ebp-101B]
. Dynamic analysis with windbg shows that this is indeed our input buffer followed by "utf8 ". For instance if we input "utf8 C:\\Windows\\System32\\cmd.exe", the string C:\\Windows\\System32\\cmd.exe
is pased into ecx . Lets deep dive into function sub_40F030
.
The function seems to be first getting foreground window and check if it is compatible with unicode strings. If yes, then only it goes ahead and gets all threads of GUI foreground. Conituing, we notice that SendInput
API is called which is generally used to synthesize keyboard strokes. Hence we might be actually typing our input in the foreground windows. To confirm this, lets set a breakpoint at 40F18E
to look at the arguments of SendInput
Looking at documentation of SendInput API, it seems that eax
contains tagINPUT structure defined as :-
The first element i.e type indicates whether its a keyboard or mouse stroke. As shown the first dword is 0x1
in our case which indicates keyboard stroke. Next is union of 3 structures i.e and since its a keyboard input there is high chance it will be indeed KEYBDINPUT structure. Lets expand this in windbg
Continuing the execution shows that the input bytes are printed in windbg output since that is the application running in foreground. We have now just a last challenge to solve for which is new line. In windows new line is denoted by \r\n
, but during the initial branch of code there is a check for \n
in sub_40bf30
where it looks for \n
initially and only considers the first part of string. Later there is also check for \r
where same strategy is being applied as code only considers first part of string without /r
.
The trick here is the check against \n
is being done by strstr
function but check against \r
is being done by a single comparision against last character of the string pointer returned by strstr
. Hence we can supply 2 \r
to make sure \r
is passed into input flow to indicate a new line.
Final Exploit :-
Thanks for reading !