115 lines
2.1 KiB
Go
115 lines
2.1 KiB
Go
/*
|
|
©AngelaMos | 2026
|
|
initd.go
|
|
|
|
Scans SysV init scripts and rc.local for persistence indicators
|
|
|
|
Checks /etc/init.d/ for non-standard scripts and /etc/rc.local for
|
|
any executable content beyond comments. Legacy persistence mechanism
|
|
that still works on many modern Linux distributions.
|
|
|
|
MITRE ATT&CK:
|
|
T1037.004 - Boot or Logon Initialization Scripts: RC Scripts
|
|
*/
|
|
|
|
package scanner
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/CarterPerez-dev/sentinel/pkg/types"
|
|
)
|
|
|
|
const (
|
|
initdScannerName = "initd"
|
|
mitreInitd = "T1037.004"
|
|
)
|
|
|
|
func init() {
|
|
Register(&InitdScanner{})
|
|
}
|
|
|
|
type InitdScanner struct{}
|
|
|
|
func (i *InitdScanner) Name() string {
|
|
return initdScannerName
|
|
}
|
|
|
|
func (i *InitdScanner) Scan(
|
|
root string,
|
|
) []types.Finding {
|
|
var findings []types.Finding
|
|
|
|
initDir := ResolveRoot(root, "/etc/init.d")
|
|
for _, path := range ListFiles(initDir) {
|
|
findings = append(
|
|
findings,
|
|
ScanFileForPatterns(
|
|
path, initdScannerName, mitreInitd,
|
|
)...,
|
|
)
|
|
|
|
if IsWorldWritable(path) {
|
|
findings = append(findings, types.Finding{
|
|
Scanner: initdScannerName,
|
|
Severity: types.SeverityMedium,
|
|
Title: "World-writable init.d script",
|
|
Path: path,
|
|
Evidence: "Any user can modify this init script",
|
|
MITRE: mitreInitd,
|
|
})
|
|
}
|
|
}
|
|
|
|
rcLocal := ResolveRoot(root, "/etc/rc.local")
|
|
findings = append(
|
|
findings,
|
|
i.scanRcLocal(rcLocal)...,
|
|
)
|
|
|
|
return findings
|
|
}
|
|
|
|
func (i *InitdScanner) scanRcLocal(
|
|
path string,
|
|
) []types.Finding {
|
|
lines := ReadLines(path)
|
|
if lines == nil {
|
|
return nil
|
|
}
|
|
|
|
hasContent := false
|
|
for _, line := range lines {
|
|
trimmed := strings.TrimSpace(line)
|
|
if trimmed == "" ||
|
|
strings.HasPrefix(trimmed, "#") ||
|
|
trimmed == "exit 0" {
|
|
continue
|
|
}
|
|
hasContent = true
|
|
break
|
|
}
|
|
|
|
if !hasContent {
|
|
return nil
|
|
}
|
|
|
|
findings := []types.Finding{{
|
|
Scanner: initdScannerName,
|
|
Severity: types.SeverityMedium,
|
|
Title: "rc.local contains executable content",
|
|
Path: path,
|
|
Evidence: "rc.local runs as root at boot",
|
|
MITRE: mitreInitd,
|
|
}}
|
|
|
|
findings = append(
|
|
findings,
|
|
ScanFileForPatterns(
|
|
path, initdScannerName, mitreInitd,
|
|
)...,
|
|
)
|
|
|
|
return findings
|
|
}
|