llm-security/signatures/malware-signatures.json
Kjell Tore Guttormsen a640f43d73 Squashed 'scanners/commons/' content from commit 0ffee85
git-subtree-dir: scanners/commons
git-subtree-split: 0ffee85a4b83b3661185488c06ed9a9994c11412
2026-08-10 20:40:16 +02:00

177 lines
10 KiB
JSON

{
"version": "0.1.0",
"id": "malware-signatures",
"description": "Known-bad-IDENTITY signatures: seven high-confidence regexes naming specific malware families - PHP webshells, reverse shells, cryptominers and offensive-security tooling. Deliberately small and tight. Complementary to the shape-based tables in this repository (entropy, taint, injection): those describe what an attack looks like, this one names things already known to be malicious. Detection data only.",
"owasp": "LLM03",
"$comment": "Extracted without behaviour change from llm-security/knowledge/signatures.json, read directly from the public remote at commit b0de0ca rather than transcribed. The seven rules are reproduced verbatim, key order included. What the seed runtime DOES with them - compiling every pattern case-insensitively, running each against a decode pipeline as well as raw bytes, filtering by an enabled-families policy, excluding certain paths, merging operator-supplied custom rules - is engine behaviour and is recorded under engine_behaviour_not_data rather than treated as part of the table.",
"provenance": {
"source_repo": "llm-security",
"source_files": [
"knowledge/signatures.json"
],
"source_consumer": "scanners/signature-scanner.mjs",
"source_version": "1.0",
"source_commit": "b0de0ca6d86ce697f39669d177c2c2654c280128",
"source_remote": "ssh://git@git.fromaitochitta.com/open/llm-security.git",
"source_bytes": 2494,
"source_sha256": "0155368f194c51e01f48e5b253067282a9c083549401a2d374afc46bb89c66bc",
"source_delivery": "read directly from the pinned commit; never transcribed through a dump",
"verified": "differentially - the seven rule objects here are compared field by field against the parsed source file, and every pattern string is byte-identical, 2026-08-09",
"evidence_limits": [
"This is an identity table, not a coverage claim. Seven signatures do not detect malware generally; they detect these seven things. A consumer that presents a clean SIG result as 'no malware' is overstating it, and the seed runtime's own header calls the table 'deliberately tight to minimize false positives'.",
"Three of the seven match on NAMES rather than on behaviour (`xmrig`, `mimikatz`, `meterpreter` and their kin). A document that merely discusses those tools matches. The seed runtime mitigates this by excluding knowledge/, tests/, docs/ and node_modules/ from the scan - a path exclusion, which is engine behaviour and does not travel with this table. A consumer without an equivalent exclusion will produce false positives this table's own severities do not warn about.",
"The provenance strings on each rule name a technique family or a public cheat sheet, not a specific sample or hash. They are attribution for the pattern's origin, not evidence that a given match is that malware."
]
},
"dialect": {
"name": "ecmascript",
"$comment": "Patterns are ECMAScript regular-expression source text exactly as the source file spells it. Unlike lexicon/injection-lexicon.json, NO rule carries a `flags` field: the engine compiles every pattern with `i` unconditionally (signature-scanner.mjs:48, `new RegExp(rule.pattern, 'i')`). Case-insensitivity is therefore engine behaviour applied to the whole table, not per-rule data. A consumer that compiles these patterns case-SENSITIVELY will silently under-match every one of them.",
"flags_applied_by_engine": "i",
"flags_declared_per_rule": "none - there is no flags field in this table",
"features_used": [
"non-capturing groups: (?:...)",
"word boundaries: \\b",
"character classes",
"negated character classes: [^...]",
"optional quantifiers: ? and *"
],
"translation_notes": [
"Python (`re`): compile with re.I. No rewriting is needed; verified by compiling all seven.",
"All seven compile in Node bare, in Node with `i`, and in Node with `iu` - 21/21 - and in Python `re` with re.I, 7/7. No pattern uses a construct that differs between the two engines.",
"No pattern contains a non-ASCII byte, and none contains the redundant `\\/` escape that appears in the other two pattern tables in this repository."
]
},
"normalisations": [],
"normalisations_note": "Empty by result, not by omission: all seven patterns are byte-identical to the source file, verified below. No escaping change was needed.",
"families": {
"$comment": "The family a rule belongs to. This is data - it is the `family` field on each rule, and the seed engine both filters on it and interpolates it into the finding title, evidence and recommendation. Note the exact spellings: `reverse_shell` with an underscore, and `cryptominer` rather than `miner`. A consumer that renames a family breaks the policy key that enables it.",
"values": [
"cryptominer",
"hacktool",
"reverse_shell",
"webshell"
],
"rule_counts": {
"cryptominer": 2,
"hacktool": 1,
"reverse_shell": 2,
"webshell": 2
},
"default_enabled": [
"webshell",
"reverse_shell",
"cryptominer",
"hacktool"
],
"default_enabled_note": "All four are enabled by default in the seed runtime (signature-scanner.mjs:30, DEFAULT_FAMILIES), in that order. Recorded because a consumer needs to know the table is fully active by default rather than opt-in; which families a given deployment enables is policy, not data."
},
"severity_vocabulary": {
"used_here": [
"critical",
"high"
],
"contract": "schema/finding.schema.json#/$defs/severity",
"$comment": "Only two of the five contract severities appear in this table. That is the table's own distribution, not a restriction on the vocabulary."
},
"rules": [
{
"id": "SIG-WEBSHELL-001",
"family": "webshell",
"severity": "critical",
"pattern": "(?:eval|assert|system|exec|passthru|shell_exec|popen|proc_open)\\s*\\(\\s*\\$_(?:POST|GET|REQUEST|COOKIE|SERVER)",
"description": "PHP webshell: executes attacker-controlled request data",
"provenance": "Classic PHP webshell pattern (c99/r57/b374k families)"
},
{
"id": "SIG-WEBSHELL-002",
"family": "webshell",
"severity": "high",
"pattern": "\\$_(?:POST|GET|REQUEST|COOKIE)\\s*\\[[^\\]]*\\]\\s*\\(",
"description": "PHP variable-function call on request data (obfuscated webshell)",
"provenance": "Variable-function webshell obfuscation"
},
{
"id": "SIG-REVSHELL-001",
"family": "reverse_shell",
"severity": "critical",
"pattern": "(?:bash|sh)\\s+-i\\s*>&?\\s*/dev/tcp/",
"description": "Bash /dev/tcp reverse shell",
"provenance": "PentestMonkey reverse-shell cheat sheet"
},
{
"id": "SIG-REVSHELL-002",
"family": "reverse_shell",
"severity": "critical",
"pattern": "\\bnc\\s+-[a-z]*e[a-z]*\\s+/(?:bin|usr/bin)/(?:sh|bash)\\b",
"description": "Netcat -e reverse shell",
"provenance": "Netcat reverse-shell one-liner"
},
{
"id": "SIG-MINER-001",
"family": "cryptominer",
"severity": "high",
"pattern": "stratum\\+(?:tcp|ssl)://",
"description": "Cryptominer stratum pool URL",
"provenance": "Stratum mining protocol"
},
{
"id": "SIG-MINER-002",
"family": "cryptominer",
"severity": "high",
"pattern": "\\b(?:xmrig|minerd|cgminer|ccminer|cpuminer)\\b",
"description": "Known cryptominer binary reference",
"provenance": "Common CPU/GPU miner binaries"
},
{
"id": "SIG-HACKTOOL-001",
"family": "hacktool",
"severity": "high",
"pattern": "\\b(?:mimikatz|meterpreter|sekurlsa::|lsadump::)\\b",
"description": "Offensive-security tooling reference",
"provenance": "Mimikatz / Metasploit Meterpreter"
}
],
"engine_behaviour_not_data": [
{
"id": "case-insensitive-compile",
"behaviour": "Every pattern is compiled with the `i` flag, unconditionally, at signature-scanner.mjs:48.",
"why_not_data": "It is applied to the table rather than declared by it. It is recorded under dialect.flags_applied_by_engine because a consumer cannot reproduce the seed behaviour without it."
},
{
"id": "decode-variant-matching",
"behaviour": "Each pattern is tested against five variants of a file's content, not just the raw bytes: raw, normalizeForScan with embedded decoding, the same on trimmed input, homoglyph-folded, and rot13 (signature-scanner.mjs:102-115). The first variant that matches wins, and a match on a non-raw variant is reported as obfuscated.",
"why_not_data": "It is the decode pipeline, which this repository does not own and deliberately does not specify. A consumer matching only raw bytes will miss obfuscated instances of these same seven signatures."
},
{
"id": "family-filter",
"behaviour": "Rules are filtered to the families named by the `sig.enabled_families` policy key before any file is read; if none are enabled the scanner returns no findings at all.",
"why_not_data": "Policy."
},
{
"id": "path-exclusion",
"behaviour": "Paths under knowledge/, tests/, docs/ and node_modules/ are skipped, because a ruleset, a fixture and a document about webshells all legitimately contain these patterns.",
"why_not_data": "Scan scoping, not detection. But see evidence_limits: without an equivalent, three of these seven rules are noisy by construction."
},
{
"id": "per-file-rule-dedup",
"behaviour": "A rule fires at most once per file, regardless of how many times it matches.",
"why_not_data": "Reporting behaviour. It means a finding count is a count of (file, rule) pairs, not of occurrences."
},
{
"id": "custom-rule-merge",
"behaviour": "Operator-supplied rules from `sig.custom_rules_path` are compiled by the same code and appended to this table at scan time.",
"why_not_data": "Runtime extension. A consumer matching only this table matches LESS than a seed deployment with custom rules loaded."
},
{
"id": "missing-field-defaults",
"behaviour": "The loader defaults a missing `family` to 'unknown', a missing `severity` to 'high', a missing `description` to the rule id, and a missing `provenance` to null, and drops any rule lacking `id` or `pattern` or whose pattern fails to compile.",
"why_not_data": "Loader tolerance. Every rule in this table carries all six fields, so no default is exercised - but a consumer writing a validator should not mistake the loader's leniency for an optional-field contract."
}
],
"totals": {
"rules": 7,
"families": 4,
"critical": 3,
"high": 4
}
}