// SPDX-License-Identifier: GPL-3.0-or-later package detectors import ( "testing" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/config" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model" ) func TestMemoryObfuscationMatchesPythonShapes(t *testing.T) { cases := []struct { name string process model.Process signature string severity string sid int }{ {"memfd", model.Process{PID: 350, Comm: "hoxha", MemoryMaps: []model.MemoryMap{{ Start: 0x1000, End: 0x2000, Perms: "r-xp", Path: "/memfd:stage (deleted)", }}}, "memory_obfuscation", "CRITICAL", SIDMemoryObfuscation}, {"anonymous-rwx", model.Process{PID: 351, Comm: "packer", MemoryMaps: []model.MemoryMap{{ Start: 0x3000, End: 0x4000, Perms: "rwxp", }}}, "memory_obfuscation", "HIGH", SIDMemoryObfuscation}, {"hide-library", model.Process{PID: 352, Comm: "bash", MemoryMaps: []model.MemoryMap{{ Start: 0x5000, End: 0x6000, Perms: "r-xp", Path: "/usr/lib/libhide.so", }}}, "process_hiding_library", "CRITICAL", SIDProcessHidingLibrary}, {"injection-library", model.Process{PID: 355, Comm: "sshd", MemoryMaps: []model.MemoryMap{{ Start: 0xb000, End: 0xc000, Perms: "r-xp", Path: "/tmp/libinject.so", }}}, "process_injection_library", "HIGH", SIDProcessInjectionLibrary}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { alerts := MemoryObfuscation(model.State{Processes: []model.Process{tc.process}}, config.Default()) if len(alerts) != 1 { t.Fatalf("expected one alert, got %#v", alerts) } if alerts[0].Signature != tc.signature || alerts[0].Severity != tc.severity || alerts[0].SID != tc.sid { t.Fatalf("unexpected alert: %#v", alerts[0]) } }) } } func TestMemoryObfuscationAllowlistsMatchPython(t *testing.T) { cfg := config.Default() if len(MemoryObfuscation(model.State{Processes: []model.Process{{ PID: 353, Comm: "node", MemoryMaps: []model.MemoryMap{{Perms: "rwxp"}}, }}}, cfg)) != 0 { t.Fatal("generic executable mapping should honor the runtime allowlist") } cfg.MemoryObfuscationAllowPaths = []string{"/tmp/known-profiler/"} if len(MemoryObfuscation(model.State{Processes: []model.Process{{ PID: 356, Comm: "python3", MemoryMaps: []model.MemoryMap{{ Perms: "r-xp", Path: "/tmp/known-profiler/libhook.so", }}, }}}, cfg)) != 0 { t.Fatal("configured mapping path should be silent") } alerts := MemoryObfuscation(model.State{Processes: []model.Process{{ PID: 354, Comm: "node", MemoryMaps: []model.MemoryMap{{ Perms: "r-xp", Path: "/tmp/libhide.so", }}, }}}, config.Default()) if len(alerts) != 1 || alerts[0].Signature != "process_hiding_library" { t.Fatalf("hide-library evidence must survive comm allowlist: %#v", alerts) } }