# Hack The Box - Smasher2

## Quick Summary

Hey guys, today smasher2 retired and here’s my write-up about it. Smasher2 was an interesting box and one of the hardest I have ever solved. Starting with a web application vulnerable to authentication bypass and RCE combined with a WAF bypass, then a kernel module with an insecure mmap handler implementation allowing users to access kernel memory. I enjoyed the box and learned a lot from it. It’s a Linux box and its ip is 10.10.10.135, I added it to /etc/hosts as smasher2.htb. Let’s jump right in!

## Nmap

As always we will start with nmap to scan for open ports and services:

We got ssh on port 22, dns on port 53 and http on port 80.

## DNS

First thing I did was to enumerate vhosts through the dns server and I got 1 result:

wonderfulsessionmanager.smasher2.htb, I added it to my hosts file.

## Web Enumeration

http://smasher2.htb had the default Apache index page:

http://wonderfulsessionmanager.smasher2.htb:

The only interesting here was the login page:

I kept testing it for a while and the responses were like this one:

It didn’t request any new pages so I suspected that it’s doing an AJAX request, I intercepted the login request to find out the endpoint it was requesting:

While browsing http://wonderfulsessionmanager.smasher2.htb I had gobuster running in the background on http://smasher2.htb/:

The only result that wasn’t 403 was /backup so I checked that and found 2 files:

Note: Months ago when I solved this box for the first time /backup was protected by basic http authentication, that wasn’t the case when I revisited the box for the write-up even after resetting it. I guess it got removed, however it wasn’t an important step, it was just heavy brute force so the box is better without it.

By looking at auth.py I knew that these files were related to wonderfulsessionmanager.smasher2.htb.

## auth.py: Analysis

auth.py:

I read the code and these are the things that interest us:
After successful authentication the server will respond with a secret key that we can use to access the endpoint /api/<key>/job:

That endpoint only accepts POST requests:

And the sent data has to be json:

Through that endpoint we can execute system commands by providing them in a parameter called schedule:

## session.so: Analysis –> Authentication Bypass

session.so is a compiled shared python library, so stands for shared object:

I opened it in ghidra and started checking the functions. Two functions caught my attention, get_internal_pwd() and get_internal_usr():

I looked at the decompiled code of both of them and noticed something strange, they were the exact same:
get_internal_pwd():

get_internal_usr():

So in theory, since the two function are identical, providing the username as a password should work. Which means that it’s just a matter of finding an existing username and we’ll be able to bypass the authentication.
I tried some common usernames before attempting to use wfuzz, Administrator worked:

## WAF Bypass –> RCE –> Shell as dzonerzy –> Root Flag

I wrote a small script to execute commands through /api/<key>/job as we saw earlier in auth.py, the script was meant for testing purposes:

Testing with whoami worked just fine:

However when I tried other commands I got a 403 response indicating that the server was protected by a WAF:

I could easily bypass it by inserting single quotes in the command:

To automate the exploitation process I wrote this small exploit:

The exploit sends 2 commands, the first one is a wget command that downloads shell.sh and the other one executes it.
shell.sh:

I hosted it on a python server and I started a netcat listener on port 1337 then I ran the exploit:

We owned user.

## dhid.ko: Enumeration

After getting a shell I copied my public ssh key to /home/dzonerzy/.ssh/authorized_keys and got ssh access.
In the home directory of dzonerzy there was a README containing a message from him saying that we’ll need to think outside the box to root smasher2:

After some enumeration, I checked the auth log and saw this line:

insmod (stands for insert module) is a tool used to load kernel modules. dhid.ko is a kernel module (ko stands for kernel object)

I checked the loaded kernel modules and that module was still loaded:

We can use modinfo to list the information about that module, as you can see it was written by dzonerzy:

Last thing I wanted to check was if there was device driver file for the module:

## dhid.ko: Analysis

I opened the module in ghidra then I started checking the functions:

The function dev_read() had a hint that this is the intended way to root the box:

One interesting function that caught my attention was dev_mmap():

In case you don’t know what mmap is, simply mmap is a system call which is used to map memory to a file or a device. (Check this)
The function dev_mmap() is a custom mmap handler.
The interesting part here is the call to remap_pfn_range() function (remap kernel memory to userspace):

I checked the documentation of remap_pfn_range() to know more about it, the function takes 5 arguments:

Description of each argument:

If we look at the function call again we can see that the 3rd and 4th arguments (physical address of the kernel memory and size of map area) are given to the function without any prior validation:

This means that we can map any size of memory we want and read/write to it, allowing us to even access the kernel memory.

## dhid.ko: Exploitation –> Root Shell –> Root Flag

Luckily, this white paper had a similar scenario and explained the exploitation process very well, I recommend reading it after finishing the write-up, I will try to explain the process as good as I can but the paper will be more detailed. In summary, what’s going to happen is that we’ll map a huge amount of memory and search through it for our process’s cred structure (The cred structure holds our process credentials) then overwrite our uid and gid with 0 and execute /bin/sh. Let’s go through it step by step.
First, we need to make sure that it’s really exploitable, we’ll try to map a huge amount of memory and check if it worked:

I compiled the code and uploaded it to the box:

Then I ran it:

From another ssh session I checked the process memory mapping, the attempt was successful:

Now we can start searching for the cred structure that belongs to our process, if we take a look at the how the cred structure looks like:

We’ll notice that the first 8 integers (representing our uid, gid, saved uid, saved gid, effective uid, effective gid, uid and gid for the virtual file system) are known to us, which represents a reliable pattern to search for in the memory:

These 8 integers are followed by a variable called securebits:

Then that variable is followed by our capabilities:

Since we know the first 8 integers we can search through the memory for that pattern, when we find a valid cred structure pattern we’ll overwrite each integer of the 8 with a 0 and check if our uid changed to 0, we’ll keep doing it until we overwrite the one which belongs to our process, then we’ll overwrite the capabilities with 0xffffffffffffffff and execute /bin/sh. Let’s try to implement the search for cred structures first.
To do that we will get our uid with getuid():

Then search for 8 consecutive integers that are equal to our uid, when we find a cred structure we’ll print its pointer and keep searching:

pwn.c:

It worked:

Now we need to overwrite the cred structure that belongs to our process, we’ll keep overwriting every cred structure we find and check our uid, when we overwrite the one that belongs to our process our uid should be 0:

pwn.c:

Great! now what’s left to do is to overwrite the capabilities in our cred structure with 0xffffffffffffffff and execute /bin/sh:

pwn.c:

And finally:

We owned root !
That’s it , Feedback is appreciated !