Initial release: offline NetScaler triage with Sigma rules and MIT license

This commit is contained in:
StasonJatham committed 2026-10-01 23:08:50 +02:00
commit 711c42b270
52 files changed
+61222

No files matched your search

+65
View File
@@ -0,0 +1,65 @@
"""Diagnostic probes must match in request context, not as ordinary prose."""
import base64
import json
import tempfile
import unittest
from pathlib import Path
from urllib.parse import quote
from netscaler_triage.engine import scan
from netscaler_triage.matching import Matcher
class CommandProbeTests(unittest.TestCase):
def test_raw_url_and_base64_probes_reach_engine(self) -> None:
commands = ["echo CHECK123&&date&&id", "id", "echo CHECK123"]
lines = []
for command in commands:
payload = quote(base64.b64encode(command.encode()).decode(), safe="")
lines.append(
"192.0.2.1 - - [01/Oct/2026:12:00:00 +0000] "
f'"GET /vpn/example.php?x={payload} HTTP/1.1" 403 0 "-" "normal"'
)
lines.append(
"Oct 1 12:00:00 adc APPFW (GET https://192.0.2.1/vpn/theme/x.php?0="
+ quote(commands[0], safe="")
+ ") <blocked>"
)
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp).resolve()
logs = root / "logs"
logs.mkdir()
(logs / "probes.log").write_text("\n".join(lines) + "\n")
scan([("ADC", logs)], root / "out", [])
findings = [
json.loads(x) for x in (root / "out/findings.jsonl").read_text().splitlines()
]
self.assertEqual(len(findings), len(lines))
for finding in findings:
self.assertTrue(
any(x["name"] == "command_injection" for x in finding["rule_details"])
)
def test_ordinary_context_does_not_trigger_probe_or_handler_rules(self) -> None:
matcher = Matcher([])
for event in [
{"raw": "id", "uri": "/health?id=42"},
{"raw": "echo CHECK123", "uri": "/search?q=echo"},
{"raw": "id", "uri": "/vpn/example.php"},
{"raw": "AddType application/x-httpd-php .php"},
{"raw": "AddType application/x-httpd-php-source .phps"},
]:
with self.subTest(event=event):
names = {x["name"] for x in matcher.search_sigma(event)}
self.assertFalse(names & {"command_injection", "ti_php_handler"})
self.assertTrue(
any(
x["name"] == "ti_php_handler"
for x in matcher.search_sigma({"raw": "AddType application/x-httpd-php .sig"})
)
)
if __name__ == "__main__":
unittest.main()