Skip to content

Commit e93915f

Browse files
authored
Add file type support for report generation (#898)
* Add file type support for report generation Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * More rules Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Tweak Discord rule Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Fix up tests Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Fix up Windows samples Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Run make yara-x-fmt Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Fix merge conflict artifacts Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Remove JSON from map Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Fix test Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Use kind.Ext instead of kind.MIME Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Fix Slack test Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Fix up rename reporting Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Add more file types to explicit_rename Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Fix up remaining PHP filetypes Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Remove redundant programkind condition Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Add more file types to rules Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * Loosen up execution policy rules Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * More rule tweaks Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> --------- Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> Signed-off-by: Evan Gibler <20933572+egibs@users.noreply.github.com>
1 parent 553cb87 commit e93915f

305 files changed

Lines changed: 795 additions & 884 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pkg/action/scan.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func scanSinglePath(ctx context.Context, c malcontent.Config, path string, ruleF
159159
return fr, nil
160160
}
161161

162-
fr, err := report.Generate(ctx, path, mrs, c, archiveRoot, logger, fc)
162+
fr, err := report.Generate(ctx, path, mrs, c, archiveRoot, logger, fc, kind)
163163
if err != nil {
164164
return nil, NewFileReportError(err, path, TypeGenerateError)
165165
}

pkg/action/testdata/scan_archive

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,31 @@
7979
],
8080
"Behaviors": [
8181
{
82-
"Description": "exhibits random behavior",
83-
"MatchStrings": [
84-
"math/rand"
85-
],
86-
"RiskScore": 2,
87-
"RiskLevel": "MEDIUM",
88-
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/anti-behavior/random_behavior.yara#go_rand",
82+
"Description": "uses a random number generator",
83+
"MatchStrings": [
84+
"getrandomUnsupported",
85+
"nonZeroRandomBytes",
86+
"startupRandomData",
87+
"readRandomUint32",
88+
"rand_getrandom",
89+
"portRandomizer",
90+
"random_vectors",
91+
"getRandomData",
92+
"extendRandom",
93+
"altGetRandom",
94+
"randomOrder",
95+
"randomPoint",
96+
"urandom_dev",
97+
"randomEnum",
98+
"nextRandom",
99+
"randomized",
100+
"randomsbom"
101+
],
102+
"RiskScore": 1,
103+
"RiskLevel": "LOW",
104+
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/anti-behavior/random_behavior.yara#random",
89105
"ID": "anti-behavior/random_behavior",
90-
"RuleName": "go_rand"
106+
"RuleName": "random"
91107
},
92108
{
93109
"Description": "Contains a table that may be used for XOR decryption",
@@ -173,6 +189,17 @@
173189
"ID": "c2/client",
174190
"RuleName": "clientID"
175191
},
192+
{
193+
"Description": "contains Cloudflare DNS resolver IP",
194+
"MatchStrings": [
195+
"1.1.1.1"
196+
],
197+
"RiskScore": 2,
198+
"RiskLevel": "MEDIUM",
199+
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/c2/discovery/ip-dns_resolver.yara#cloudflare_dns_ip",
200+
"ID": "c2/discovery/ip_dns_resolver",
201+
"RuleName": "cloudflare_dns_ip"
202+
},
176203
{
177204
"Description": "references a specific architecture",
178205
"MatchStrings": [
@@ -1071,7 +1098,8 @@
10711098
{
10721099
"Description": "renames files",
10731100
"MatchStrings": [
1074-
"os.rename"
1101+
"os.rename",
1102+
"os.Rename"
10751103
],
10761104
"RiskScore": 1,
10771105
"RiskLevel": "LOW",
@@ -1080,15 +1108,15 @@
10801108
"RuleName": "explicit_rename"
10811109
},
10821110
{
1083-
"Description": "access filesystem metadata",
1111+
"Description": "access filesystem information",
10841112
"MatchStrings": [
1085-
"fs.statDirEntry"
1113+
"_stat"
10861114
],
1087-
"RiskScore": 1,
1088-
"RiskLevel": "LOW",
1089-
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/file/file-stat.yara#npm_stat",
1115+
"RiskScore": 0,
1116+
"RiskLevel": "NONE",
1117+
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/file/file-stat.yara#stat",
10901118
"ID": "fs/file/stat",
1091-
"RuleName": "npm_stat"
1119+
"RuleName": "stat"
10921120
},
10931121
{
10941122
"Description": "forcibly synchronizes file state to disk",

pkg/programkind/programkind.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,19 @@ var supportedKind = map[string]string{
7171
"h": "text/x-h",
7272
"hh": "text/x-h",
7373
"html": "",
74+
"jar": "application/java-archive",
7475
"java": "text/x-java",
7576
"js": "application/javascript",
77+
"ko": "application/x-object",
7678
"lnk": "application/x-ms-shortcut",
7779
"lua": "text/x-lua",
80+
"M": "text/x-objectivec",
81+
"m": "text/x-objectivec",
7882
"macho": "application/x-mach-binary",
83+
"mm": "text/x-objectivec",
7984
"md": "",
8085
"o": "application/octet-stream",
86+
"pe": "application/vnd.microsoft.portable-executable",
8187
"php": "text/x-php",
8288
"pl": "text/x-perl",
8389
"pm": "text/x-script.perl-module",
@@ -209,7 +215,7 @@ func makeFileType(path string, ext string, mime string) *FileType {
209215
return Path(".elf")
210216
}
211217

212-
if strings.Contains(mime, "application") || strings.Contains(mime, "text/x-") || strings.Contains(mime, "text/x-") || strings.Contains(mime, "executable") {
218+
if strings.Contains(mime, "application") || strings.Contains(mime, "text/x-") || strings.Contains(mime, "executable") {
213219
return &FileType{
214220
Ext: ext,
215221
MIME: mime,

pkg/report/report.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/chainguard-dev/clog"
1919
"github.com/chainguard-dev/malcontent/pkg/malcontent"
20+
"github.com/chainguard-dev/malcontent/pkg/programkind"
2021

2122
yarax "github.com/VirusTotal/yara-x/go"
2223
)
@@ -364,8 +365,20 @@ func TrimPrefixes(path string, prefixes []string) string {
364365
return path
365366
}
366367

368+
// fileMatchesRules checks the scanned file's type against a rule's defined filetypes.
369+
func fileMatchesRule(meta []yarax.Metadata, ext string) bool {
370+
for _, m := range meta {
371+
if m.Identifier() == "filetypes" {
372+
filetypes := strings.Split(fmt.Sprintf("%s", m.Value()), ",")
373+
return slices.Contains(filetypes, ext)
374+
}
375+
}
376+
// Rules without filetype metadata are universal
377+
return true
378+
}
379+
367380
//nolint:cyclop // ignore complexity of 64
368-
func Generate(ctx context.Context, path string, mrs *yarax.ScanResults, c malcontent.Config, expath string, _ *clog.Logger, fc []byte) (*malcontent.FileReport, error) {
381+
func Generate(ctx context.Context, path string, mrs *yarax.ScanResults, c malcontent.Config, expath string, _ *clog.Logger, fc []byte, kind *programkind.FileType) (*malcontent.FileReport, error) {
369382
if ctx.Err() != nil {
370383
return &malcontent.FileReport{}, ctx.Err()
371384
}
@@ -425,6 +438,10 @@ func Generate(ctx context.Context, path string, mrs *yarax.ScanResults, c malcon
425438
ignoreMalcontent = true
426439
}
427440

441+
if !fileMatchesRule(m.Metadata(), kind.Ext) {
442+
continue
443+
}
444+
428445
override := slices.Contains(m.Tags(), "override")
429446

430447
risk = behaviorRisk(m.Namespace(), m.Identifier(), m.Tags())

rules/anti-behavior/LD_DEBUG.yara

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
rule env_LD_DEBUG: medium {
22
meta:
33
description = "may check if dynamic linker debugging is enabled"
4+
filetypes = "elf,macho"
45

56
strings:
67
$val = "LD_DEBUG" fullword

rules/anti-behavior/LD_PROFILE.yara

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
rule env_LD_PROFILE: medium {
22
meta:
33
description = "may check if dynamic linker profiling is enabled"
4+
filetypes = "elf,macho"
45

56
strings:
67
$val = "LD_PROFILE" fullword

rules/anti-behavior/anti-debugger.yara

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
rule win_debugger_present: medium windows {
22
meta:
33
description = "Detects if process is being executed within a debugger"
4+
filetypes = "exe,pe,ps1"
45

56
strings:
67
$debug_idp = "IsDebuggerPresent"
@@ -13,6 +14,7 @@ rule win_debugger_present: medium windows {
1314
rule win_debugger_or_vm: medium windows {
1415
meta:
1516
description = "Detects if process is being executed within a debugger or VM"
17+
filetypes = "exe,pe,ps1"
1618

1719
strings:
1820
$cpu_pfp = "IsProcessorFeaturePresent"
@@ -27,6 +29,7 @@ rule win_debugger_or_vm: medium windows {
2729
rule multiple_linux_methods: high linux {
2830
meta:
2931
description = "possible debugger detection across multiple methods"
32+
filetypes = "elf"
3033

3134
strings:
3235
$ld_profile = "LD_PROFILE" fullword

rules/anti-behavior/process-check.yara

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
rule activity_monitor_checker: high macos {
22
meta:
33
description = "checks if 'Activity Monitor' is running"
4+
filetypes = "macho"
45

56
strings:
67
$ps = "ps" fullword
@@ -16,6 +17,7 @@ rule activity_monitor_checker: high macos {
1617
rule linux_monitors: high linux {
1718
meta:
1819
description = "checks if various process monitors are running"
20+
filetypes = "elf"
1921

2022
strings:
2123
$pgrep = "pgrep" fullword
@@ -45,6 +47,7 @@ rule linux_monitors: high linux {
4547
rule anti_rootkit_hunter: high linux {
4648
meta:
4749
description = "checks if rootkit detectors are running"
50+
filetypes = "elf"
4851

4952
strings:
5053
$proc = "/proc/"

rules/anti-behavior/random_behavior.yara

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ private rule random_behavior_pythonSetup {
2020
rule setuptools_random: critical {
2121
meta:
2222
description = "Python library installer that exhibits random behavior"
23+
filetypes = "py"
2324

2425
strings:
2526
$ref = "import random"
@@ -32,6 +33,7 @@ rule setuptools_random: critical {
3233
rule java_random: low {
3334
meta:
3435
description = "exhibits random behavior"
36+
filetypes = "java"
3537

3638
strings:
3739
$ref = "java/util/Random"
@@ -43,6 +45,7 @@ rule java_random: low {
4345
rule go_rand: medium {
4446
meta:
4547
description = "exhibits random behavior"
48+
filetypes = "go"
4649

4750
strings:
4851
$ref = "math/rand"
@@ -54,6 +57,7 @@ rule go_rand: medium {
5457
rule rand_call: medium {
5558
meta:
5659
description = "exhibits random behavior"
60+
filetypes = "c,pl,php"
5761

5862
strings:
5963
$ref = "rand()"

rules/anti-static/base64/eval.yara

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import "math"
33
rule eval_base64: high {
44
meta:
55
description = "Evaluates base64 content"
6+
filetypes = "js,ts"
67

78
strings:
89
$eval = /eval\(.{0,256}base64/
@@ -14,6 +15,7 @@ rule eval_base64: high {
1415
rule ruby_eval_base64_decode: critical {
1516
meta:
1617
description = "Evaluates base64 content"
18+
filetypes = "rb"
1719

1820
strings:
1921
$eval_base64_decode = "eval(Base64."
@@ -25,6 +27,7 @@ rule ruby_eval_base64_decode: critical {
2527
rule ruby_eval_near_enough: high {
2628
meta:
2729
description = "Evaluates base64 content"
30+
filetypes = "rb"
2831

2932
strings:
3033
$eval = "eval("
@@ -37,6 +40,7 @@ rule ruby_eval_near_enough: high {
3740
rule ruby_eval2_near_enough: high {
3841
meta:
3942
description = "Evaluates base64 content"
43+
filetypes = "rb"
4044

4145
strings:
4246
$eval = "eval("
@@ -49,6 +53,7 @@ rule ruby_eval2_near_enough: high {
4953
rule python_exec_near_enough_base64: high {
5054
meta:
5155
description = "Likely executes base64 content"
56+
filetypes = "py"
5257

5358
strings:
5459
$exec = "exec("
@@ -61,6 +66,7 @@ rule python_exec_near_enough_base64: high {
6166
rule python_base64_exec: critical {
6267
meta:
6368
description = "executes compressed base64 content"
69+
filetypes = "py"
6470

6571
strings:
6672
$dec_b64decode_exec = /.{0,8}\.decompress\(.{0,96}\.b64decode\(.{0,64}\Wexec\(.{0,16}/

0 commit comments

Comments
 (0)