feat(go): advance validation sidecar toward production
This commit is contained in:
parent
6a06eba255
commit
f85c2e831a
92 changed files with 8881 additions and 91 deletions
123
go-agent/internal/events/syscall_rules.go
Normal file
123
go-agent/internal/events/syscall_rules.go
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model"
|
||||
)
|
||||
|
||||
const (
|
||||
protWrite = 0x2
|
||||
protExec = 0x4
|
||||
ptraceTrace = 0
|
||||
ptraceAttach = 16
|
||||
ptraceSeize = 0x4206
|
||||
prSetSeccomp = 22
|
||||
)
|
||||
|
||||
type syscallPredicate func(SyscallEvent) bool
|
||||
|
||||
type SyscallRule struct {
|
||||
SID int
|
||||
Message string
|
||||
Severity string
|
||||
Classtype string
|
||||
Syscalls map[string]bool
|
||||
Predicate syscallPredicate
|
||||
}
|
||||
|
||||
func (r SyscallRule) Matches(event SyscallEvent) bool {
|
||||
return r.Syscalls[event.Syscall] && r.Predicate(event)
|
||||
}
|
||||
|
||||
func (r SyscallRule) Alert(event SyscallEvent) model.Alert {
|
||||
detail := fmt.Sprintf(
|
||||
"sid=%d %s — pid=%d ppid=%d comm=%s syscall=%s args=[%#x, %#x, %#x, %#x]",
|
||||
r.SID, r.Message, event.PID, event.PPID, event.Comm, event.Syscall,
|
||||
event.Args[0], event.Args[1], event.Args[2], event.Args[3])
|
||||
if event.Text != "" {
|
||||
detail += " text=[" + truncateRunes(event.Text, 80) + "]"
|
||||
}
|
||||
return model.Alert{
|
||||
SID: r.SID, Severity: r.Severity,
|
||||
Signature: "syscall_rule." + r.Classtype, Classtype: r.Classtype,
|
||||
Key: fmt.Sprintf("syscall:%d:%d:%s:%x:%x",
|
||||
r.SID, event.PID, event.Syscall, event.Args[0], event.Args[2]),
|
||||
Detail: detail, PIDs: []int{event.PID},
|
||||
}
|
||||
}
|
||||
|
||||
type SyscallRuleEngine struct {
|
||||
Rules []SyscallRule
|
||||
}
|
||||
|
||||
func DefaultSyscallRuleEngine() SyscallRuleEngine {
|
||||
return SyscallRuleEngine{Rules: []SyscallRule{
|
||||
{
|
||||
SID: 100060, Message: "mprotect made memory writable and executable",
|
||||
Severity: "CRITICAL", Classtype: "memory-obfuscation",
|
||||
Syscalls: stringSet([]string{"mprotect"}),
|
||||
Predicate: func(event SyscallEvent) bool { return protectedWX(event.Args[2]) },
|
||||
},
|
||||
{
|
||||
SID: 100061, Message: "mmap requested writable and executable memory",
|
||||
Severity: "CRITICAL", Classtype: "memory-obfuscation",
|
||||
Syscalls: stringSet([]string{"mmap"}),
|
||||
Predicate: func(event SyscallEvent) bool { return protectedWX(event.Args[2]) },
|
||||
},
|
||||
{
|
||||
SID: 100062, Message: "memfd_create used for anonymous in-memory file staging",
|
||||
Severity: "MEDIUM", Classtype: "fileless-execution",
|
||||
Syscalls: stringSet([]string{"memfd_create"}), Predicate: alwaysSyscall,
|
||||
},
|
||||
{
|
||||
SID: 100063, Message: "ptrace anti-debug or attach operation observed",
|
||||
Severity: "HIGH", Classtype: "anti-analysis",
|
||||
Syscalls: stringSet([]string{"ptrace"}),
|
||||
Predicate: func(event SyscallEvent) bool {
|
||||
request := event.Args[0]
|
||||
return request == ptraceTrace || request == ptraceAttach || request == ptraceSeize
|
||||
},
|
||||
},
|
||||
{
|
||||
SID: 100064,
|
||||
Message: "seccomp sandboxing call observed (possible anti-analysis hardening)",
|
||||
Severity: "MEDIUM", Classtype: "anti-analysis",
|
||||
Syscalls: stringSet([]string{"prctl", "seccomp"}),
|
||||
Predicate: func(event SyscallEvent) bool {
|
||||
return event.Syscall == "seccomp" || event.Args[0] == prSetSeccomp
|
||||
},
|
||||
},
|
||||
{
|
||||
SID: 100065, Message: "cross-process memory read/write syscall observed",
|
||||
Severity: "HIGH", Classtype: "credential-access",
|
||||
Syscalls: stringSet([]string{"process_vm_readv", "process_vm_writev"}),
|
||||
Predicate: alwaysSyscall,
|
||||
},
|
||||
{
|
||||
SID: 100066,
|
||||
Message: "memory locking syscall observed (possible protected in-memory payload)",
|
||||
Severity: "MEDIUM", Classtype: "memory-obfuscation",
|
||||
Syscalls: stringSet([]string{"mlock", "mlock2", "mlockall"}),
|
||||
Predicate: alwaysSyscall,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
func (e SyscallRuleEngine) Match(event SyscallEvent) []model.Alert {
|
||||
alerts := make([]model.Alert, 0)
|
||||
for _, rule := range e.Rules {
|
||||
if rule.Matches(event) {
|
||||
alerts = append(alerts, rule.Alert(event))
|
||||
}
|
||||
}
|
||||
return alerts
|
||||
}
|
||||
|
||||
func protectedWX(protection uint64) bool {
|
||||
return protection&protWrite != 0 && protection&protExec != 0
|
||||
}
|
||||
|
||||
func alwaysSyscall(SyscallEvent) bool { return true }
|
||||
Loading…
Add table
Add a link
Reference in a new issue