Introduction to Runner:
This walkthrough will explore the “Runner” machine from Hack the Box, categorized as a Hard difficulty challenge. This walkthrough will cover the reconnaissance, exploitation, and privilege escalation steps required to capture the flag.
http://hacktheboxltd.sjv.io/darknite
Objective:
The goal of this walkthrough is to complete the “Runner” machine from Hack The Box by achieving the following objectives:
User Flag:
Initial Exploitation:
- Exploit the authentication bypass vulnerability to generate an API token.
Data Access and Recovery:
- Use the token to either enable debug mode and run system commands or create an admin user to access a backup, which provides password hashes and an SSH key.
Root Flag:
Exploiting Vulnerable runc
Binary:
- Challenge: Exploit a vulnerable
runc
binary through Portainer. - Twist: Unlike typical POCs that assume Docker group access, this scenario doesn’t grant such privileges.
Enumerating the Runner Machine
Reconnaissance:
Nmap Scan:
Begin with a network scan to identify open ports and running services on the target machine.
nmap -sC -sV -oA initial 10.10.11.13
Nmap Output:
┌─[darknite@parrot]─[~/Documents/htb/runner]
└──╼ $nmap -sC -sV 10.10.11.13 -oA initial
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-23 18:34 EDT
Nmap scan report for 10.10.11.13
Host is up (0.17s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (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 27.95 seconds
Analysis on runner machine:
- Port 22/tcp: Open, running OpenSSH 8.9p1 on Ubuntu, with ECDSA and ED25519 host keys.
- Port 80/tcp: Open, running nginx 1.18.0 on Ubuntu, but did not follow the redirect to
http://runner.htb/
. - Port 8000/tcp: Open, running Nagios NSCA, but the HTTP title is not set.
Web Enumeration on Runner
Perform web enumeration to discover potentially exploitable directories and files
gobuster dir -u http://10.10.11.13 -w /opt/Seclists/Discovery/Web-Content/raft-small-directories.txt
Gobuster Output:
┌─[darknite@parrot]─[~/Documents/htb/runner]
└──╼ $gobuster dir -u http://runner.htb -w /opt/SecLists/Discovery/Web-Content/raft-small-directories.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://runner.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /opt/SecLists/Discovery/Web-Content/raft-small-directories.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/assets (Status: 301) [Size: 178] [--> http://runner.htb/assets/]
Progress: 20116 / 20117 (100.00%)
===============================================================
Finished
===============================================================
Analysis:
Status Code 301 (Redirect):
Discovered path:
- /assets: Redirects to
http://runner.htb/assets/
The /assets
directory returns a 301-status code, indicating it permanently redirects to the specified URL. The response size is 178 bytes.
Access the Website Interface on runner machine
To proceed, open the web browser and navigate to the website interface.
No useful information was found; the path is straightforward with no additional content to explore.
┌─[darknite@parrot]─[~/Documents/htb/runner]
└──╼ $gobuster vhost -u http://runner.htb -w /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://runner.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
[+] Append Domain: false
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Progress: 4989 / 4990 (99.98%)
===============================================================
Finished
===============================================================
┌─[darknite@parrot]─[~/Documents/htb/runner]
└──╼ $gobuster vhost -u http://runner.htb -w /opt/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://runner.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /opt/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
[+] Append Domain: false
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Progress: 100000 / 100001 (100.00%)
===============================================================
Finished
===============================================================
Performed vhost enumeration on http://runner.htb
with Gobuster using two wordlists:
subdomains-top1million-5000.txt
- Progress: 99.98%
- Checked: 4989 of 4990
bitquark-subdomains-top100000.txt
- Progress: 100%
- Checked: 100,000 of 100,001
Both scans were completed, but no new virtual hosts were found.
┌─[darknite@parrot]─[~/Documents/htb/runner]
└──╼ $ffuf -u http://runner.htb -w /opt/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt -H "Host: FUZZ.runner.htb" -fw 4
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://runner.htb
:: Wordlist : FUZZ: /opt/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt
:: Header : Host: FUZZ.runner.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response words: 4
________________________________________________
teamcity [Status: 401, Size: 66, Words: 8, Lines: 2, Duration: 345ms]
:: Progress: [100000/100000] :: Job [1/1] :: 1273 req/sec :: Duration: [0:01:14] :: Errors: 0 ::
┌─[darknite@parrot]─[~/Documents/htb/runner]
└──╼ $
FFUF Scan Results:
Executed a subdomain scan against http://runner.htb
using the wordlist bitquark-subdomains-top100000.txt
with the Host header set to FUZZ.runner.htb
.
- Endpoint Found:
TeamCity
- Status: 401 Unauthorized
- Response Size: 66 bytes
- Response Words: 8
The only subdomain found was TeamCity
, which returned a 401 status.
TeamCity Enumeration
What is TeamCity?
TeamCity is a continuous integration and continuous deployment (CI/CD) server developed by JetBrains. It helps automate the process of building, testing, and deploying software. Here’s a brief rundown of what it does:
Build Management: Automates building and testing code to ensure it's ready for deployment.
Continuous Integration: Integrates code changes into a shared repository frequently to detect issues early.
Deployment Pipelines: Manages the release of software to various environments (development, testing, production).
In a CTF context, finding a TeamCity instance might indicate a system involved in the development and deployment process, which could be a potential target for further exploitation or enumeration.
TeamCity by JetBrains automates software builds, tests, and deployments. It handles code integration and manages releases across different environments. In a CTF scenario, finding a TeamCity server might point to a system involved in development and deployment, making it a key target for further exploration or attacks.
We’ve found the TeamCity login page but don’t have any credentials yet. This is our starting point for further exploration and potential access.
CVE-2023-42793
JetBrains TeamCity 2023.05.3 – Remote Code Execution (RCE) (CVE-2023-42793)
- Vulnerability: Remote Code Execution (RCE)
- CVE: CVE-2023-42793
- Version Affected: TeamCity 2023.05.3
- Details: This vulnerability allows attackers to execute arbitrary code on the TeamCity server remotely.
- Impact:
- Full Server Control: Exploiting this issue can let attackers take over the server.
- Possible Actions: Run any commands, access or modify data, and potentially disrupt the service.
- How It Works: Attackers send specially crafted requests to trigger the RCE vulnerability and execute malicious code.
TeamCity CVE-2023-42793 Exploit
This Python script exploits the CVE-2023-42793 vulnerability in JetBrains TeamCity, allowing the creation of a new admin user.
How it works?
Run the script with either one or multiple TeamCity URLs that are vulnerable to CVE-2023-42793.
For a single URL:
python exploit.py -u http://teamcity.example.com
Here’s a concise description of the manual help of the Python script
Log in to TeamCity using the credentials obtained through the CVE exploit with our newly created account.
We have successfully accessed the dashboard.
No builds are currently queued.
In the Administration tab, we can create a project, which may help us gather additional useful information.
Navigate to the Backup tab, initiate the backup process, and download the resulting zip file to your machine.
Download the backup zip file to our machine.
Extract the contents of the zip file.
Within the backup, focus on extracting user password hashes and the SSH private key. We managed to locate the id_rsa
at /config/projects/Allproject/plugindata/ssh_keys
.
The user with administrative privileges is identified as john
.
Let’s access the machine using John’s potential SSH key.
We can view the user flag by executing the command cat
user.txt
.
Escalate to Root Privileges
To gain root access, follow the necessary steps to escalate privileges.
We found a new domain or subdomain /etc/hosts
that could be leveraged for further escalation.
We encounter a login page for Portainer.
What is Portainer?
Portainer Community Edition (CE) is our core offering, widely used by over half a million users. It’s an open-source tool that simplifies building and managing containers across Docker, Docker Swarm, Kubernetes, and Azure ACI.
Portainer Business Edition (BE) is the commercial version tailored for enterprises. It includes advanced features like Role-Based Access Control, registry management, and dedicated support, providing robust container management across Docker, Docker Swarm, Kubernetes, and Azure ACI.
We identified a Matthew account that can be accessed by obtaining its password hash from the backup.
We can use Matthew’s access to attempt command execution on the shell.
Let’s set up a volume using some unconventional parameters
The vulnerability can be exploited in two main ways:
- Set the container’s working directory to
/proc/self/fd/8
. - Create a symlink for
/proc/self/fd/8
. When commands are run inside the container usingdocker exec
orkubectl exec
with the working directory set to this symlink, attackers can access the host’s filesystem through/proc/<PID>/cwd
, where<PID
>
is the process ID from thedocker exec
orkubectl exec
command.
As per this post, we need to create a container with the working directory set to /proc/self/fd/8
. Now, use the teamcity:latest
image to create this container.
The details provided will reveal the information as described above.
Set up the configuration as detailed above.
Launch the Docker container as outlined above.
We need to escalate the user’s privileges from a normal user to root.
Finally, we have root access.
We can execute a shell to get a reverse connection.
We can read the root flag now.
No responses yet