ONNX
security
malware-detection
Vigil / source /pkg /bundle /analyzer_script_other.go
turentomer's picture
Publish self-contained Vigil distribution
d2507b5 verified
Raw
History Blame Contribute Delete
3.07 kB
package bundle
import "strings"
// ScriptOtherAnalyzer covers the executable-text formats the threat model says
// scanners ignore: .mjs/.cjs/.ts/.rb/.ps1/.bat/.lua/.pl and by-name
// Makefile/Dockerfile/justfile (KindScriptOther). It reuses the shared
// language-agnostic source/sink vocabulary plus a per-language family pass so
// no executable text format stays sub-threshold.
type ScriptOtherAnalyzer struct{}
func (ScriptOtherAnalyzer) Name() string { return "script-other" }
func (ScriptOtherAnalyzer) Handles(kind FileKind) bool { return kind == KindScriptOther }
// scriptOtherIndicatorFamilies maps a language/format to the network-sink and
// exec primitives that, when paired with an env/secret read, indicate exfil.
// These augment the shared vocabulary with idioms specific to each runtime.
var scriptOtherIndicatorFamilies = map[string][]string{
"node": {"child_process", "require('child_process')", "exec(", "execsync(", "spawn(", "https.request", "http.request", "net.connect"},
"ruby": {"net::http", "open-uri", "open(\"|", "system(", "`", "%x{", "exec(", "io.popen"},
"powershell": {"invoke-webrequest", "invoke-restmethod", "iwr ", "irm ", "start-process", "downloadstring", "system.net.webclient", "invoke-expression", "iex "},
"batch": {"powershell", "bitsadmin", "certutil -urlcache", "start /b", "reg add"},
"lua": {"os.execute", "io.popen", "socket.http", "require(\"socket"},
"perl": {"lwp::useragent", "system(", "exec(", "`", "io::socket", "use net::"},
"make": {"curl ", "wget ", "$(shell", "&& sh", "| sh", "| bash"},
"docker": {"run curl", "run wget", "run pip", "run npm", "add http", "&& sh", "| sh"},
}
func (ScriptOtherAnalyzer) Analyze(f *File, b *Bundle) ([]Finding, error) {
if f == nil {
return nil, nil
}
text := string(f.Sniff)
out := sharedIndicatorScan(text, f.RelPath, "script-other")
// Per-language: a runtime exec/network primitive co-occurring with an
// env/secret source is SevHigh+Corroborated even when the shared vocab
// missed the exact sink token.
lang := strings.ToLower(f.ScriptLang)
fam := scriptOtherIndicatorFamilies[lang]
if len(fam) > 0 {
lines := strings.Split(text, "\n")
lower := make([]string, len(lines))
for i, l := range lines {
lower[i] = strings.ToLower(l)
}
for i := range lower {
window := lower[i]
if i+1 < len(lower) {
window += "\n" + lower[i+1]
}
if i+2 < len(lower) {
window += "\n" + lower[i+2]
}
hasPrimitive := matchedAny(window, fam)
hasSource := matchedAny(window, envSourceTerms)
if hasPrimitive && hasSource {
out = append(out, Finding{
Analyzer: "script-other",
File: f.RelPath,
Signal: "exfil-env-to-network",
Severity: SevHigh,
Detail: lang + " runtime exec/network primitive co-occurs with env/credential read",
Line: i + 1,
Corroborated: true,
})
}
}
}
if pe, ok := paddingEvasionFinding(f, "script-other"); ok {
out = append(out, pe)
}
return dedupeFindings(out), nil
}