mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 02:14:39 +00:00
fix(security): close shell deny gaps for halt, su, doas, pkexec, runuser
Add missing deny patterns discovered during security audit: - destructive_ops: halt, init/telinit 0|6, systemctl suspend/hibernate - privilege_escalation: broaden su to block all forms (bare su, su root), add doas, pkexec (CVE-2021-4034), runuser
This commit is contained in:
1 parent
0973b842a2
commit
94f6bf2445
2 files changed
+97
-3
No files matched your search
@@ -28,8 +28,10 @@ var DenyGroupRegistry = map[string]*DenyGroup{
|
||||
regexp.MustCompile(`\b(mkfs|diskpart)\b|\bformat\s`),
|
||||
regexp.MustCompile(`\bdd\s+if=`),
|
||||
regexp.MustCompile(`>\s*/dev/sd[a-z]\b`),
|
||||
regexp.MustCompile(`\b(shutdown|reboot|poweroff)\b`),
|
||||
regexp.MustCompile(`:\(\)\s*\{.*\};\s*:`), // fork bomb
|
||||
regexp.MustCompile(`\b(shutdown|reboot|poweroff|halt)\b`),
|
||||
regexp.MustCompile(`\b(init|telinit)\s+[06]\b`), // SysV shutdown/reboot
|
||||
regexp.MustCompile(`\bsystemctl\s+(suspend|hibernate)\b`), // power management
|
||||
regexp.MustCompile(`:\(\)\s*\{.*\};\s*:`), // fork bomb
|
||||
},
|
||||
},
|
||||
"data_exfiltration": {
|
||||
@@ -81,7 +83,10 @@ var DenyGroupRegistry = map[string]*DenyGroup{
|
||||
Default: true,
|
||||
Patterns: []*regexp.Regexp{
|
||||
regexp.MustCompile(`\bsudo\b`),
|
||||
regexp.MustCompile(`\bsu\s+-`),
|
||||
regexp.MustCompile(`\bsu\b`),
|
||||
regexp.MustCompile(`\bdoas\b`),
|
||||
regexp.MustCompile(`\bpkexec\b`),
|
||||
regexp.MustCompile(`\brunuser\b`),
|
||||
regexp.MustCompile(`\bnsenter\b`),
|
||||
regexp.MustCompile(`\bunshare\b`),
|
||||
regexp.MustCompile(`\b(mount|umount)\b`),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -49,6 +50,94 @@ func TestBase64DecodeShellDeny(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// mustDeny asserts all commands match at least one pattern.
|
||||
func mustDeny(t *testing.T, patterns []*regexp.Regexp, commands ...string) {
|
||||
t.Helper()
|
||||
for _, cmd := range commands {
|
||||
matched := false
|
||||
for _, p := range patterns {
|
||||
if p.MatchString(cmd) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
t.Errorf("expected deny for %q", cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mustAllow asserts no command matches any pattern.
|
||||
func mustAllow(t *testing.T, patterns []*regexp.Regexp, commands ...string) {
|
||||
t.Helper()
|
||||
for _, cmd := range commands {
|
||||
for _, p := range patterns {
|
||||
if p.MatchString(cmd) {
|
||||
t.Errorf("unexpected deny for %q (matched %s)", cmd, p.String())
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestructiveOpsGaps(t *testing.T) {
|
||||
patterns := DenyGroupRegistry["destructive_ops"].Patterns
|
||||
|
||||
mustDeny(t, patterns,
|
||||
// existing
|
||||
"shutdown", "reboot", "poweroff",
|
||||
"shutdown -h now", "reboot -f",
|
||||
// new: halt
|
||||
"halt", "halt -p", "systemctl halt",
|
||||
// new: init/telinit
|
||||
"init 0", "init 6", "telinit 0", "telinit 6",
|
||||
// new: systemctl suspend/hibernate
|
||||
"systemctl suspend", "systemctl hibernate",
|
||||
)
|
||||
|
||||
mustAllow(t, patterns,
|
||||
"halting the process", // "halt" inside word
|
||||
"initialize", // "init" inside word
|
||||
"initial setup", // "init" inside word
|
||||
"init_db", // no space+digit after init
|
||||
"init 1", // only 0 and 6 are blocked
|
||||
"systemctl status", // not suspend/hibernate
|
||||
"systemctl start nginx",
|
||||
)
|
||||
}
|
||||
|
||||
func TestPrivilegeEscalationGaps(t *testing.T) {
|
||||
patterns := DenyGroupRegistry["privilege_escalation"].Patterns
|
||||
|
||||
mustDeny(t, patterns,
|
||||
// existing
|
||||
"sudo ls", "sudo -i",
|
||||
// su: all forms now blocked
|
||||
"su", "su -", "su root", "su -l postgres", "su admin",
|
||||
// new: doas
|
||||
"doas reboot", "doas ls /root", "doas -u www sh",
|
||||
// new: pkexec
|
||||
"pkexec vim /etc/passwd", "pkexec /bin/bash",
|
||||
// new: runuser
|
||||
"runuser -l postgres", "runuser -u nobody -- /bin/sh",
|
||||
// existing
|
||||
"nsenter --target 1", "unshare -m", "mount /dev/sda1 /mnt",
|
||||
)
|
||||
|
||||
mustAllow(t, patterns,
|
||||
"summit", // not "su"
|
||||
"sugar", // not "su"
|
||||
"surplus", // not "su"
|
||||
"issue", // not "su"
|
||||
"result", // not "su"
|
||||
"resume", // not "su"
|
||||
"visual", // not "su"
|
||||
"sushi", // not "su"
|
||||
"doaspkg", // not "doas" (no word boundary)
|
||||
"pkexecute", // not "pkexec" (no word boundary)
|
||||
)
|
||||
}
|
||||
|
||||
func TestLimitedBuffer(t *testing.T) {
|
||||
t.Run("under limit", func(t *testing.T) {
|
||||
lb := &limitedBuffer{max: 100}
|
||||
|
||||
Reference in new issue
Block a user