root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat builder.md
// writeups

Builder

12 Feb 2024 · 24 min read · root access
Builder - maquina de Hack The Box

Executive summary — Builder exposes a Jenkins 2.441 instance with anonymous read enabled, which turns CVE-2024-23897 (arbitrary file read via the HTTP CLI and args4j's @file expansion) into exploitable without any credentials. That flaw leaks the sole administrator's bcrypt hash, which falls in seconds against rockyou.txt, and admin access unlocks the Script Console for arbitrary Groovy execution inside the controller's JVM. The real escalation isn't just another file leak: it's asking Jenkins's own credentials API to decrypt, in memory, the root SSH key for the host running the container.

PlatformHack The Box
Operating systemLinux
DifficultyMedium
StatusRetired
Target IP10.129.230.220

Attack map

[8080] Jenkins 2.441 (Jetty) — anonymous "Overall/Read" enabled
   │  X-Jenkins: 2.441 + "Dashboard" title (no login prompt) -> CVE-2024-23897
   ▼
[CLI-HTTP]  jenkins-cli.jar connect-node "@file" (args4j expandAtFiles)
   │  arbitrary file read -> users.xml, config.xml (bcrypt hash), credentials.xml
   ▼
[CRACK]  hashcat -m 3200 + rockyou.txt -> jennifer:princess (admin)
   │  Script Console (/scriptText) -> arbitrary Groovy in the controller JVM
   ▼
[RCE]  jenkins, inside a Docker container   (user.txt)
   │  credentials.xml stores an ENCRYPTED root SSH key
   │  CredentialsProvider.lookupCredentials() -> Jenkins decrypts it for us
   ▼
[SSH]  root@10.129.230.220, on the HOST   (root.txt)

1. Reconnaissance

With the HTB VPN up, a quick connectivity check already gives a first hint about the OS:

ping -c 3 10.129.230.220
64 bytes from 10.129.230.220: icmp_seq=1 ttl=63 time=36.5 ms
64 bytes from 10.129.230.220: icmp_seq=2 ttl=63 time=36.7 ms
64 bytes from 10.129.230.220: icmp_seq=3 ttl=63 time=36.0 ms

A ttl=63 lines up with a Linux default TTL of 64, minus the VPN gateway's hop (Windows would answer near 127). From there, a full port sweep prioritizing speed over stealth — this is a lab:

sudo nmap -p- --min-rate 5000 -T4 -Pn -oN nmap_allports.txt 10.129.230.220
PORT      STATE    SERVICE
22/tcp    open     ssh
6426/tcp  filtered unknown
8080/tcp  open     http-proxy
59084/tcp filtered unknown

The filtered ports are HTB VPN noise; the ones that matter are 22 and 8080. Service/version detection on both:

sudo nmap -p22,8080 -sCV -Pn -oN nmap_services.txt 10.129.230.220
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
8080/tcp open  http    Jetty 10.0.18
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
| http-robots.txt: 1 disallowed entry
|_/
|_http-title: Dashboard [Jenkins]
|_http-server-header: Jetty(10.0.18)

OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 confirms Ubuntu 22.04 "Jammy". The detail that decides the whole machine is the title: Dashboard [Jenkins], not Sign in to Jenkins. That can only mean the anonymous user has read permission (Overall/Read) and the dashboard is visible without authenticating — exactly the requirement the initial-exploitation bug needs to be usable without credentials.

Jenkins publishes its version in HTTP headers without needing to authenticate:

curl -s -I http://10.129.230.220:8080/
HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-Hudson-Theme: default
X-Hudson: 1.395
X-Jenkins: 2.441
X-Jenkins-Session: 728bcbe5
X-Instance-Identity: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoLwaR1Kew...
Server: Jetty(10.0.18)

X-Jenkins: 2.441 points straight at CVE-2024-23897 (published January 24, 2024), affecting weekly releases up to 2.441 and the LTS line up to 2.426.2 — meaning 2.441 is exactly the last vulnerable version. Before touching the CVE, the anonymous REST API confirms the read access and enumerates what's configured:

curl -s "http://10.129.230.220:8080/api/json?pretty=true"
{
  "_class" : "hudson.model.Hudson",
  "mode" : "NORMAL",
  "nodeDescription" : "the Jenkins controller's built-in node",
  "numExecutors" : 2,
  "jobs" : [ ],
  "slaveAgentPort" : 50000,
  "useCrumbs" : true,
  "useSecurity" : true
}

With no jobs configured, the usual "create a malicious job" route is off the table from the start. But the API still lets us enumerate users:

curl -s "http://10.129.230.220:8080/asynchPeople/api/json?pretty=true"
{
  "users" : [
    {
      "user" : {
        "absoluteUrl" : "http://10.129.230.220:8080/user/jennifer",
        "fullName" : "jennifer"
      }
    }
  ]
}

A single user, jennifer. With anonymous read plus CVE-2024-23897 confirmed and a username in hand, it's time to read her configuration.

🔒 Clearance required

This content is Root Access only. Everything else on the site — the free tier, the whole public library — stays open.

See Root Access plans

No account? Create one free then upgrade from your console.