Document importing from a Nuclei template, and what the importer refuses
A CVE record describes a vulnerability, not a request, which is why this channel is written by hand. A Nuclei template contains the request — path, query, headers, body — because that is what it sends, so for thousands of CVEs the shape a virtual patch needs is already written down. What cannot come across is the template's matchers: they read the RESPONSE to decide whether the target was actually vulnerable, and a WAF decides before a response exists. So an imported rule is strictly weaker than the template it came from — it recognises the attempt, not the exploitation. That is why they land as action "log", which the engine now honours: observed, recorded as an event, scoring nothing. Also records what the importer skips rather than guesses: a CVE already patched in compiled code, a request that is entirely template variables, a literal under twelve characters, the site root. And what it corrects: one leading path segment, because a template is written against a laboratory where the application is mounted somewhere — /laravel52/vendor/phpunit/... would have been published unable to match a real attack at /vendor/phpunit/... Documentation only. cve.json is untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N5fpE6Gu4W6JoFMXyb7t7r
This commit is contained in:
1 parent
1e0ad6cd7b
commit
d8426a1d6c
1 file changed
+54
@@ -57,6 +57,60 @@ only one it may clear, which is also what makes a rule **withdrawable**: remove
|
|||||||
it, bump the stamp, and it stops being enforced everywhere within the hour.
|
it, bump the stamp, and it stops being enforced everywhere within the hour.
|
||||||
Publishing an empty `"rulesets": []` withdraws the lot.
|
Publishing an empty `"rulesets": []` withdraws the lot.
|
||||||
|
|
||||||
|
|
||||||
|
## Importing from a Nuclei template
|
||||||
|
|
||||||
|
A CVE record describes a vulnerability, not a request, which is why this
|
||||||
|
channel is written by hand. A **Nuclei template** does contain the request —
|
||||||
|
path, query, headers, body — because that is what it sends. So for thousands of
|
||||||
|
CVEs the shape a virtual patch needs is already written down.
|
||||||
|
|
||||||
|
go run ./tools/nuclei-importer -cves CVE-2025-31161,CVE-2024-4577 \
|
||||||
|
-merge edgeguard-rules/cve.json > /tmp/next.json
|
||||||
|
cp /tmp/next.json edgeguard-rules/cve.json
|
||||||
|
bash tools/publish-cve-feed.sh --check
|
||||||
|
|
||||||
|
**Imported rules land as `action: "log"`, and that is not timidity.** A template
|
||||||
|
decides whether a target was actually vulnerable by reading the RESPONSE —
|
||||||
|
words in the body, the content type, the status. A WAF decides before a
|
||||||
|
response exists, so the imported rule is strictly weaker than the template it
|
||||||
|
came from: the template confirms exploitation, the rule only recognises the
|
||||||
|
attempt. Watch what it would have caught in your own traffic, then change
|
||||||
|
`log` to `block` deliberately, per rule.
|
||||||
|
|
||||||
|
Each imported rule carries an `origin` field saying a human did not write its
|
||||||
|
pattern and what it came from. Do not remove it — it is the difference between
|
||||||
|
a rule somebody reasoned about and one a converter guessed.
|
||||||
|
|
||||||
|
### What it refuses to do
|
||||||
|
|
||||||
|
It skips rather than guesses, and prints why:
|
||||||
|
|
||||||
|
- **A CVE the engine already patches in code.** Both rules would fire and the
|
||||||
|
scores would add. Five are patched today: the two PHP2Shell ones, Log4Shell
|
||||||
|
(two) and Spring4Shell.
|
||||||
|
- **A request with nothing literal in it.** Templates are full of
|
||||||
|
`{{BaseURL}}` and `{{string_1}}`; a pattern that is mostly `.*` matches
|
||||||
|
ordinary traffic.
|
||||||
|
- **A request whose longest literal is under twelve characters**, or is the
|
||||||
|
site root. A rule on `/` matches everything.
|
||||||
|
|
||||||
|
### What it corrects, and why you should check anyway
|
||||||
|
|
||||||
|
It strips one leading path segment when three remain, because a template is
|
||||||
|
written against a laboratory where the application is mounted somewhere: the
|
||||||
|
phpunit template requests `/laravel52/vendor/phpunit/...` and `laravel52` is
|
||||||
|
that lab's directory. Without stripping it the rule is published, enabled, and
|
||||||
|
unable to match a real attack at `/vendor/phpunit/...`.
|
||||||
|
|
||||||
|
It prefers a header value carrying an injection marker (`${jndi:`, `<%`, `$(`,
|
||||||
|
`../`) over a path, and ignores standard headers entirely whatever their value.
|
||||||
|
An earlier version preferred headers over everything and produced the pattern
|
||||||
|
`Content-Type: text/html` for a PHP RCE — a rule that says nothing about the
|
||||||
|
attack and something about every request.
|
||||||
|
|
||||||
|
None of that makes the output right. Read every pattern before publishing.
|
||||||
|
|
||||||
## Targets
|
## Targets
|
||||||
|
|
||||||
The usual ones (`uri`, `query`, `args`, `body`, `headers`, `user_agent`,
|
The usual ones (`uri`, `query`, `args`, `body`, `headers`, `user_agent`,
|
||||||
|
|||||||
Reference in new issue
Block a user