ONNX
security
malware-detection
File size: 3,067 Bytes
d2507b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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
}