65 lines
2.4 KiB
Python
65 lines
2.4 KiB
Python
"""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()
|