Skip to content

Drupal enumeration

5 min read Created Jan 23, 2026 Last updated Apr 24, 2026

Drupal enumeration identifies the installed version, active modules, themes, and user accounts. The version is the critical signal: Drupal 7 and older Drupal 8 releases have well-known RCE vulnerabilities including Drupalgeddon2 and Drupalgeddon3. Run this after tech fingerprinting confirms Drupal.

Key Drupal paths to probe early:

  • /CHANGELOG.txt: version disclosure (Drupal 7)
  • /core/CHANGELOG.txt: version disclosure (Drupal 8/9/10)
  • /install.txt, /core/INSTALL.txt: confirms Drupal presence
  • /sites/all/modules/: contributed module directory (Drupal 7)
  • /modules/: module directory (Drupal 8+)
  • /?q=user/login: login form, useful for user enumeration
  • /?q=admin: admin panel accessibility
  • /?q=user/register: open registration check

Confirm Drupal and Version

Version is often disclosed in the changelog or install.txt files before any tooling is needed:

┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/CHANGELOG.txt | head -5
Drupal 7.57, 2018-02-21
Explain command
-s Silent mode; suppresses progress meter and error messages.
-k Allow insecure TLS connections, skipping certificate verification.
http://$TARGET_IP:$PORT/CHANGELOG.txt Target URL using variable host and port to fetch CHANGELOG.txt.
head -5 Pipes output and displays only the first 5 lines.
┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/core/CHANGELOG.txt | head -5
Explain command
-s Silent mode; suppresses progress meter and error messages.
-k Allow insecure SSL connections by skipping certificate verification.
http://$TARGET_IP:$PORT/core/CHANGELOG.txt Target URL with variable host IP and port to fetch CHANGELOG.txt.
head -5 Pipes output and displays only the first 5 lines.
┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/install.txt | head -5
Explain command
-s Silent mode; suppresses progress meter and error messages.
-k Allow insecure TLS connections, skipping certificate verification.
http://$TARGET_IP:$PORT/install.txt Target URL with variable host and port to fetch install.txt.
head -5 Pipes output and displays only the first 5 lines.

Drupal 7 uses /CHANGELOG.txt. Drupal 8 and 9 use /core/CHANGELOG.txt. If the files are removed, check the meta generator tag:

┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/ | grep -i 'generator\|drupal'
<meta name="generator" content="Drupal 7 (https://www.drupal.org)" />
Explain command
-s Silent mode; suppresses progress and error messages.
-k Allow insecure TLS connections, skipping certificate verification.
http://$TARGET_IP:$PORT/ Target URL built from host IP and port placeholders.
-i Makes the grep pattern matching case-insensitive.
'generator\|drupal' Regex pattern matching 'generator' or 'drupal' in output.

droopescan

droopescan enumerates modules, themes, and version ranges passively. It's slower than manual checks but more thorough on module discovery:

┌──(kali㉿kali)-[~]
└─$ droopescan scan drupal -u http://$TARGET_IP:$PORT/
[+] Plugins found:
    views http://10.10.10.50/sites/all/modules/views/
    token http://10.10.10.50/sites/all/modules/token/

[+] Themes found:
    bartik http://10.10.10.50/themes/bartik/

[+] Possible version(s):
    7.57
Explain command
scan Subcommand to initiate a scan against the target CMS.
drupal Specifies Drupal as the target CMS type to scan.
-u Specifies the target URL to scan.
http://$TARGET_IP:$PORT/ Target URL with variable IP address and port number.

User Enumeration

Drupal 7 leaks usernames through login error messages and the node/user system. Confirm with a direct probe:

┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/?q=user/1
Explain command
-s Silent mode; suppresses progress meter and error messages.
-k Allow insecure connections; skip SSL/TLS certificate verification.
http://$TARGET_IP:$PORT/?q=user/1 Target URL with host, port, and query string to fetch user record 1.
┌──(kali㉿kali)-[~]
└─$ curl -sk -d 'name=admin&pass=wrongpassword&form_id=user_login&op=Log+in' http://$TARGET_IP:$PORT/?q=user/login | grep -i 'error\|unrecognized'
Sorry, unrecognized username or password.
Explain command
-s Silent mode; suppresses progress meter and error messages.
-k Allow insecure SSL connections, skipping certificate verification.
-d Send specified data as HTTP POST request body.
'name=admin&pass=wrongpassword&form_id=user_login&op=Log+in' POST body with Drupal login form fields including credentials.
http://$TARGET_IP:$PORT/?q=user/login Target URL with IP, port placeholders, and Drupal login path.
-i Case-insensitive pattern matching in grep.
'error\|unrecognized' Grep pattern matching 'error' or 'unrecognized' in response output.

If the error says "unrecognized username" for a non-existent user but "incorrect password" for a valid one, the application is vulnerable to username enumeration.

Admin Panel and Registration Check

Check whether registration is open and the admin panel is reachable:

┌──(kali㉿kali)-[~]
└─$ curl -sk -o /dev/null -w '%{http_code}' http://$TARGET_IP:$PORT/?q=admin
200
Explain command
-s Silent mode; suppresses progress meter and error messages.
-k Allow insecure TLS connections, skipping certificate verification.
-o /dev/null Discard response body by writing output to /dev/null.
-w '%{http_code}' Print the HTTP response status code after the request completes.
http://$TARGET_IP:$PORT/?q=admin Target URL with dynamic IP, port, and query string parameter q=admin.
┌──(kali㉿kali)-[~]
└─$ curl -sk -o /dev/null -w '%{http_code}' http://$TARGET_IP:$PORT/?q=user/register
Explain command
-s Silent mode; suppresses progress and error output.
-k Allow insecure TLS connections, skipping certificate verification.
-o /dev/null Discard response body by redirecting output to /dev/null.
-w '%{http_code}' Print only the HTTP response status code after the request.
http://$TARGET_IP:$PORT/?q=user/register Target URL with variable host/port probing the Drupal user register path.

Module and Theme Path Probing

Probe known module paths to identify which are installed without droopescan:

┌──(kali㉿kali)-[~]
└─$ ffuf -w /usr/share/seclists/Discovery/Web-Content/CMS/drupal-modules.txt -u http://$TARGET_IP:$PORT/sites/all/modules/FUZZ/ -mc 200,301,302,403
Explain command
-w /usr/share/seclists/Discovery/Web-Content/CMS/drupal-modules.txt Wordlist file containing Drupal module names for fuzzing.
-u http://$TARGET_IP:$PORT/sites/all/modules/FUZZ/ Target URL with FUZZ keyword as the injection point.
$TARGET_IP:$PORT Variable placeholders for the target host IP and port.
-mc 200,301,302,403 Match only responses with these HTTP status codes.

A Drupal 7 install on a vulnerable version is a high-priority finding. Drupalgeddon2 (CVE-2018-7600) affects Drupal 6, 7, and 8 before specific patch versions and gives unauthenticated RCE. Cross-reference the version against known CVEs before moving to exploitation.

References