Initial release: offline NetScaler triage with Sigma rules and MIT license
This commit is contained in:
commit
711c42b270
52 files changed
+61222
No files matched your search
@@ -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()
|
||||
Reference in new issue
Block a user