<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: writing-cms-detection-templates
description: >-
  Write Nuclei templates for detecting Content Management Systems,
  their versions, installed plugins, exposed admin panels, default
  configurations, and known CMS-specific vulnerabilities across
  WordPress, Joomla, Drupal, and other platforms.
domain: cybersecurity
subdomain: nuclei-templating
tags:
  - nuclei
  - cms
  - detection
  - wordpress
  - joomla
  - drupal
  - templates
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1190"]
---

# Writing CMS Detection Templates

## Overview

CMS detection templates identify content management systems, extract version
information, enumerate plugins and themes, and detect CMS-specific
misconfigurations. Accurate CMS fingerprinting enables targeted vulnerability
scanning against the specific platform and its ecosystem of extensions.

Mode: `[MODE: RECON]` — CMS fingerprinting and ecosystem enumeration.

## Prerequisites

| Requirement | Details |
|---|---|
| Nuclei v3+ (`nuclei -version`) | Required |
| Understanding of major CMS platforms and their file structures | Required |
| Target websites running CMS platforms | Required |

## Key Concepts

### WordPress Detection and Version Extraction

```yaml
id: wordpress-version-detection

info:
  name: WordPress Version Detection
  author: nerf
  severity: info
  description: |
    Detects WordPress installations and extracts the exact version
    from meta generators, RSS feeds, and readme files. Version
    information enables targeted CVE scanning.
  tags: cms,wordpress,detection,version
  metadata:
    max-request: 3

http:
  - method: GET
    path:
      - "{{BaseURL}}/"
      - "{{BaseURL}}/feed/"
      - "{{BaseURL}}/readme.html"
    stop-at-first-match: false

    matchers-condition: or
    matchers:
      - type: word
        part: body
        words:
          - "wp-content"
          - "wp-includes"
          - "WordPress"
        condition: or
    extractors:
      - type: regex
        part: body
        regex:
          - 'content="WordPress\s+([0-9.]+)"'
          - '<generator>https://wordpress.org/\?v=([0-9.]+)</generator>'
          - 'Version\s+([0-9.]+)'
        group: 1
```

### WordPress Plugin Enumeration

```yaml
id: wordpress-plugin-enumeration

info:
  name: WordPress Plugin Enumeration
  author: nerf
  severity: info
  description: |
    Enumerates installed WordPress plugins by probing common plugin
    paths and analyzing page source for plugin references. Discovered
    plugins can be cross-referenced with vulnerability databases.
  tags: cms,wordpress,plugin,enumeration
  metadata:
    max-request: 8

http:
  - method: GET
    path:
      - "{{BaseURL}}/wp-content/plugins/contact-form-7/readme.txt"
      - "{{BaseURL}}/wp-content/plugins/woocommerce/readme.txt"
      - "{{BaseURL}}/wp-content/plugins/elementor/readme.txt"
      - "{{BaseURL}}/wp-content/plugins/wordfence/readme.txt"
      - "{{BaseURL}}/wp-content/plugins/jetpack/readme.txt"
      - "{{BaseURL}}/wp-content/plugins/akismet/readme.txt"
      - "{{BaseURL}}/wp-content/plugins/yoast-seo/readme.txt"
      - "{{BaseURL}}/wp-content/plugins/wp-super-cache/readme.txt"

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - "Stable tag:"
          - "=== Description ==="
        condition: or
      - type: status
        status:
          - 200
    extractors:
      - type: regex
        part: body
        regex:
          - 'Stable tag:\s*([0-9.]+)'
        group: 1
```

### Joomla Detection

```yaml
id: joomla-detection

info:
  name: Joomla CMS Detection
  author: nerf
  severity: info
  description: |
    Detects Joomla CMS installations and extracts version from
    manifest files and admin pages. Identifies exposed admin
    panels and configuration artifacts.
  tags: cms,joomla,detection,version
  metadata:
    max-request: 3

http:
  - method: GET
    path:
      - "{{BaseURL}}/administrator/manifests/files/joomla.xml"
      - "{{BaseURL}}/language/en-GB/en-GB.xml"
      - "{{BaseURL}}/administrator/"

    matchers-condition: or
    matchers:
      - type: word
        part: body
        words:
          - "<name>Joomla"
          - "Joomla!"
          - "com_login"
        condition: or
    extractors:
      - type: regex
        part: body
        regex:
          - '<version>([0-9.]+)</version>'
        group: 1
```

### Drupal Detection

```yaml
id: drupal-detection

info:
  name: Drupal CMS Detection
  author: nerf
  severity: info
  description: |
    Detects Drupal CMS installations and extracts version from
    changelog, update status, and meta tags. Identifies exposed
    admin paths and configuration files.
  tags: cms,drupal,detection,version
  metadata:
    max-request: 3

http:
  - method: GET
    path:
      - "{{BaseURL}}/CHANGELOG.txt"
      - "{{BaseURL}}/core/CHANGELOG.txt"
      - "{{BaseURL}}/user/login"

    matchers-condition: or
    matchers:
      - type: word
        part: body
        words:
          - "Drupal"
          - "drupal.org"
        condition: or
    extractors:
      - type: regex
        part: body
        regex:
          - 'Drupal\s+([0-9.]+)'
        group: 1
```

### CMS Admin Panel Exposure

```yaml
id: cms-admin-panel-exposure

info:
  name: CMS Admin Panel Exposure Detection
  author: nerf
  severity: low
  description: |
    Detects publicly accessible CMS admin login panels. Exposed
    admin panels are targets for brute force attacks and should
    be protected with IP restrictions or VPN access.
  classification:
    cwe-id: CWE-200
  tags: cms,admin,exposure,misconfig
  metadata:
    max-request: 5

http:
  - method: GET
    path:
      - "{{BaseURL}}/wp-admin/"
      - "{{BaseURL}}/wp-login.php"
      - "{{BaseURL}}/administrator/"
      - "{{BaseURL}}/user/login"
      - "{{BaseURL}}/admin/"
    stop-at-first-match: true

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - "password"
          - "login"
          - "username"
        condition: and
      - type: status
        status:
          - 200
```

## Workflow

### Step 1: Validate Template

```bash
nuclei -t cms-detection.yaml -validate
```

### Step 2: Fingerprint CMS

```bash
node scripts/agent.js --action scan --target https://example.com \
  --template cms-detection.yaml --output /tmp/cms-fingerprint.json
```

### Step 3: Enumerate Plugins

```bash
node scripts/agent.js --action scan --target https://wordpress-site.com \
  --template wp-plugin-enum.yaml --output /tmp/plugin-enum.json
```

## Verification

- [ ] Templates check multiple CMS-specific file paths
- [ ] Version extractors use regex with capture groups
- [ ] Plugin enumeration covers popular/vulnerable plugins
- [ ] Admin panel detection confirms login form presence
- [ ] No false positives from generic 200 responses
- [ ] `stop-at-first-match` used where one match suffices
- [ ] `max-request` metadata matches actual request count

## References

- [Nuclei HTTP Protocol](https://docs.projectdiscovery.io/templates/protocols/http/basic-http)
- [WordPress REST API](https://developer.wordpress.org/rest-api/)
- [WPScan Vulnerability Database](https://wpscan.com/vulnerabilities)
- [Joomla Security Centre](https://developer.joomla.org/security-centre.html)
