173 lines
4.9 KiB
Python
173 lines
4.9 KiB
Python
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
"""Compatibility tests for rule event JSON evolution."""
|
|
import unittest
|
|
|
|
from enodia_sentinel import ruleops
|
|
from enodia_sentinel.config import Config
|
|
|
|
|
|
class TestRuleEventCompatibility(unittest.TestCase):
|
|
def setUp(self):
|
|
self.cfg = Config()
|
|
|
|
def _sids(self, event):
|
|
return {a.sid for a in ruleops.test_event(self.cfg, event)}
|
|
|
|
def test_exec_event_accepts_type_alias(self):
|
|
event = {
|
|
"type": "execve",
|
|
"pid": "4242",
|
|
"ppid": "1",
|
|
"uid": "1000",
|
|
"parent_comm": "nginx",
|
|
"filename": "/usr/bin/sh",
|
|
"argv": ["-c", "id"],
|
|
}
|
|
self.assertIn(100003, self._sids(event))
|
|
|
|
def test_exec_event_kind_can_be_inferred_from_fields(self):
|
|
event = {
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 1000,
|
|
"parent_comm": "bash",
|
|
"filename": "/tmp/payload",
|
|
"argv": [],
|
|
}
|
|
self.assertIn(100001, self._sids(event))
|
|
|
|
def test_syscall_event_accepts_type_alias_and_numeric_strings(self):
|
|
event = {
|
|
"type": "sys",
|
|
"pid": "4242",
|
|
"ppid": "1",
|
|
"uid": "1000",
|
|
"comm": "loader",
|
|
"syscall": "mprotect",
|
|
"args": ["0x1000", "0x1000", "0x6"],
|
|
}
|
|
self.assertIn(100060, self._sids(event))
|
|
|
|
def test_syscall_event_kind_can_be_inferred_from_fields(self):
|
|
event = {
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 1000,
|
|
"comm": "loader",
|
|
"syscall": "memfd_create",
|
|
}
|
|
self.assertIn(100062, self._sids(event))
|
|
|
|
def test_syscall_arg_fields_override_args_array(self):
|
|
event = {
|
|
"event": "syscall",
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 1000,
|
|
"comm": "loader",
|
|
"syscall": "mmap",
|
|
"args": [0, 4096, 0],
|
|
"arg2": "0x6",
|
|
}
|
|
self.assertIn(100061, self._sids(event))
|
|
|
|
def test_host_event_accepts_tcp_connect_shape(self):
|
|
event = {
|
|
"event": "tcp_connect",
|
|
"pid": "4242",
|
|
"ppid": "1",
|
|
"uid": "1000",
|
|
"comm": "python3",
|
|
"remote_ip": "8.8.8.8",
|
|
"remote_port": "4444",
|
|
}
|
|
self.assertIn(100067, self._sids(event))
|
|
|
|
def test_host_event_accepts_listen_shape(self):
|
|
event = {
|
|
"type": "listen",
|
|
"pid": "4242",
|
|
"ppid": "1",
|
|
"uid": "1000",
|
|
"comm": "python3",
|
|
"bind_ip": "0.0.0.0",
|
|
"bind_port": "4444",
|
|
}
|
|
self.assertIn(100068, self._sids(event))
|
|
|
|
def test_host_event_accepts_file_write_shape(self):
|
|
self.assertIn(100069, self._sids({
|
|
"event": "file_write",
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 1000,
|
|
"comm": "python3",
|
|
"path": "/etc/systemd/system/evil.service",
|
|
}))
|
|
|
|
def test_host_event_accepts_chmod_and_setuid_shapes(self):
|
|
self.assertIn(100070, self._sids({
|
|
"event": "chmod",
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 0,
|
|
"comm": "chmod",
|
|
"path": "/etc/cron.d/evil",
|
|
"mode": "0o777",
|
|
}))
|
|
self.assertIn(100071, self._sids({
|
|
"event": "setuid",
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 1000,
|
|
"comm": "python3",
|
|
"target_uid": "0",
|
|
}))
|
|
|
|
def test_host_event_accepts_bind_accept_capset_and_module_shapes(self):
|
|
self.assertIn(100073, self._sids({
|
|
"type": "bind",
|
|
"pid": "4242",
|
|
"ppid": "1",
|
|
"uid": "1000",
|
|
"comm": "python3",
|
|
"bind_ip": "0.0.0.0",
|
|
"bind_port": "4444",
|
|
}))
|
|
self.assertIn(100076, self._sids({
|
|
"event": "accept",
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 1000,
|
|
"comm": "python3",
|
|
"remote_ip": "8.8.8.8",
|
|
"remote_port": "51515",
|
|
"local_port": "4444",
|
|
}))
|
|
self.assertIn(100077, self._sids({
|
|
"event": "capset",
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 1000,
|
|
"comm": "python3",
|
|
"capability": "CAP_SYS_ADMIN",
|
|
}))
|
|
self.assertIn(100078, self._sids({
|
|
"event": "module_load",
|
|
"pid": 4242,
|
|
"ppid": 1,
|
|
"uid": 0,
|
|
"comm": "insmod",
|
|
"path": "/tmp/evil.ko",
|
|
"name": "evil",
|
|
}))
|
|
|
|
def test_unknown_event_shape_still_errors(self):
|
|
with self.assertRaisesRegex(
|
|
ValueError, "event JSON must be an exec, syscall, or host event"
|
|
):
|
|
ruleops.test_event(self.cfg, {"pid": 4242})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|