← all walkthroughs

Giveback

Linux· Medium· Credential Access· Privilege Escalation
owned
2026-10-11
time to own
22m12s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I found a WordPress site on a Kubernetes-hosted server running an outdated Give donation plugin. An unauthenticated object-deserialization flaw in the plugin gave code execution inside the WordPress container. An environment variable in that container pointed to an internal legacy CMS.

That CMS used a vulnerable PHP-CGI configuration, which gave root inside a second container and access to its Kubernetes service-account token. The token read cluster secrets, which exposed a reusable password for the host user babywyrm. Over SSH, that user could run a runc-based debug wrapper through sudo.

The wrapper's runc 1.1.11 had a file-descriptor leak that allowed a container escape to host root. Full host compromise followed.

Command conventions

The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.

export TARGET="<retired-instance-ip>"
export INTERNAL_HOST="<another-host-reached-after-pivoting>"

Attack path — how the box was taken

1EnumerationService and CMS enumeration; REST API user disclosure (T1595, T1087)
Mapped exposed services and identified the WordPress stack
A port sweep of $TARGET showed SSH (22), a WordPress site behind nginx (80) and a Go service on 30686. The Give donation plugin was an outdated version, and the WordPress REST API disclosed the username babywyrm.
Ports 22, 80 and 30686 open; Kubernetes, nginx, PHP and WordPress identified; form ID 17 enumerated on the donation page.
FixPatch the Give plugin and restrict WordPress information disclosureCritical
WeaknessThe Give donation plugin was outdated and vulnerable to unauthenticated deserialization RCE (CVE-2024-5932). The REST API also exposed valid usernames.
FixUpdate Give to the current release and enable automatic plugin updates. Restrict the REST users endpoint to authenticated callers. Put a web application firewall in front of the site.
2Initial AccessPHP object deserialization RCE, CVE-2024-5932 (T1190)
Gained code execution in the WordPress container through the Give plugin
The outdated Give plugin (CVE-2024-5932) deserialized my own input from an unauthenticated donation request. This gave remote code execution, and the callback landed in a pod named beta-vino-wp-wordpress as uid=1001 with the root group.
Inbound connection from the target to the listener; id returned uid=1001 gid=0(root); hostname was a Kubernetes pod name.
3Discovery and PivotEnvironment discovery and TCP tunnelling to an internal service (T1046, T1090)
Found an internal legacy CMS through Kubernetes service variables
The pod's environment contained LEGACY_INTRANET_SERVICE_PORT=tcp://$INTERNAL_HOST:5000, a ClusterIP service not reachable from outside the cluster. I tunnelled to it so it could be tested from my machine.
LEGACY_INTRANET_SERVICE_PORT=tcp://$INTERNAL_HOST:5000; the service was reached on local port 222.
FixSegment internal services with Kubernetes NetworkPoliciesHigh
WeaknessThe public WordPress pod could reach an internal legacy intranet service, and its environment advertised the service's address.
FixApply default-deny NetworkPolicies and allow only the specific flows each pod needs. Set enableServiceLinks: false in pod specs to stop service variables being injected.
4ExploitationPHP-CGI argument injection, CVE-2024-4577 (T1190)
Achieved root in the legacy CMS container through PHP-CGI argument injection
The legacy CMS kept Windows-style php-cgi handling after migration. A crafted query string injected PHP configuration options, so the request body ran as code. This produced uid=0 inside the second pod, legacy-intranet-cms.
The response to an id request returned uid=0(root); the hostname was legacy-intranet-cms-6f7bf5db84-lfw7l.
FixRetire or patch the legacy PHP-CGI CMS and run it unprivilegedCritical
WeaknessThe legacy CMS used a PHP-CGI setup vulnerable to argument injection (CVE-2024-4577) and ran as root in its container.
FixUpgrade PHP to a fixed release, or retire the service. Use PHP-FPM instead of CGI. Run the container as a non-root user with a read-only root filesystem and dropped capabilities.
5Credential AccessKubernetes service-account abuse and credential reuse (T1552.007, T1078)
Used the pod's service-account token to read cluster secrets and log in over SSH
The root-in-container shell could read the mounted Kubernetes service-account token. The token was authorized to list secrets in the namespace. Those secrets held a password for the host user babywyrm and database passwords. The user's password worked over SSH on the host, and user.txt was read as <user.txt>.
SSH as babywyrm returned uid=1000(babywyrm); user.txt captured and accepted as <user.txt>.
FixLimit service-account permissions and stop storing host passwords in cluster secretsCritical
WeaknessThe pod's service account could list secrets in its namespace. Those secrets held a host user's password, which was reusable over SSH.
FixDisable token auto-mounting where it is not needed (automountServiceAccountToken: false). Apply least-privilege RBAC that denies secret listing. Never store host login passwords in Kubernetes secrets. Rotate every exposed credential.
6Privilege Escalationrunc CVE-2024-21626 container escape via sudo-permitted wrapper (T1611, T1548.003)
Escaped a container through the sudo-permitted runc wrapper to become host root
Sudo -l showed babywyrm could run only /opt/debug, a wrapper around runc 1.1.11. The wrapper's second administrative password was a recovered database secret. Runc 1.1.11 is vulnerable to CVE-2024-21626, a leaked file descriptor that lets a container's working directory point at the host filesystem. With a container spec I controlled, this gave read access to /root and host root. root.txt was read as <root.txt>.
Wrapper reported runc version 1.1.11; the container ran as uid=0 and read the host's root flag as <root.txt>.
FixUpgrade runc and remove the sudo-permitted runc wrapperCritical
Weaknessbabywyrm could run a runc wrapper as root through sudo. The runc version, 1.1.11, was vulnerable to CVE-2024-21626, and the wrapper's extra password came from a reused database secret.
FixUpgrade runc to 1.1.12 or later. Remove the /opt/debug sudo rule, or replace it with a fixed-purpose command that does not accept user-supplied container specs. Use unique credentials that are not shared with other systems.

Exposed services

22/tcp
80/tcp
30686/tcp