Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion pkg/action/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func scanSinglePath(ctx context.Context, c malcontent.Config, path string, ruleF
return fr, nil
}

fr, err := report.Generate(ctx, path, mrs, c, archiveRoot, logger, fc)
fr, err := report.Generate(ctx, path, mrs, c, archiveRoot, logger, fc, kind)
if err != nil {
return nil, NewFileReportError(err, path, TypeGenerateError)
}
Expand Down
58 changes: 43 additions & 15 deletions pkg/action/testdata/scan_archive
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,31 @@
],
"Behaviors": [
{
"Description": "exhibits random behavior",
"MatchStrings": [
"math/rand"
],
"RiskScore": 2,
"RiskLevel": "MEDIUM",
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/anti-behavior/random_behavior.yara#go_rand",
"Description": "uses a random number generator",
"MatchStrings": [
"getrandomUnsupported",
"nonZeroRandomBytes",
"startupRandomData",
"readRandomUint32",
"rand_getrandom",
"portRandomizer",
"random_vectors",
"getRandomData",
"extendRandom",
"altGetRandom",
"randomOrder",
"randomPoint",
"urandom_dev",
"randomEnum",
"nextRandom",
"randomized",
"randomsbom"
],
"RiskScore": 1,
"RiskLevel": "LOW",
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/anti-behavior/random_behavior.yara#random",
"ID": "anti-behavior/random_behavior",
"RuleName": "go_rand"
"RuleName": "random"
},
{
"Description": "Contains a table that may be used for XOR decryption",
Expand Down Expand Up @@ -173,6 +189,17 @@
"ID": "c2/client",
"RuleName": "clientID"
},
{
"Description": "contains Cloudflare DNS resolver IP",
"MatchStrings": [
"1.1.1.1"
],
"RiskScore": 2,
"RiskLevel": "MEDIUM",
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/c2/discovery/ip-dns_resolver.yara#cloudflare_dns_ip",
"ID": "c2/discovery/ip_dns_resolver",
"RuleName": "cloudflare_dns_ip"
},
{
"Description": "references a specific architecture",
"MatchStrings": [
Expand Down Expand Up @@ -1071,7 +1098,8 @@
{
"Description": "renames files",
"MatchStrings": [
"os.rename"
"os.rename",
"os.Rename"
],
"RiskScore": 1,
"RiskLevel": "LOW",
Expand All @@ -1080,15 +1108,15 @@
"RuleName": "explicit_rename"
},
{
"Description": "access filesystem metadata",
"Description": "access filesystem information",
"MatchStrings": [
"fs.statDirEntry"
"_stat"
],
"RiskScore": 1,
"RiskLevel": "LOW",
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/file/file-stat.yara#npm_stat",
"RiskScore": 0,
"RiskLevel": "NONE",
"RuleURL": "https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/file/file-stat.yara#stat",
"ID": "fs/file/stat",
"RuleName": "npm_stat"
"RuleName": "stat"
},
{
"Description": "forcibly synchronizes file state to disk",
Expand Down
8 changes: 7 additions & 1 deletion pkg/programkind/programkind.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,19 @@ var supportedKind = map[string]string{
"h": "text/x-h",
"hh": "text/x-h",
"html": "",
"jar": "application/java-archive",
"java": "text/x-java",
"js": "application/javascript",
"ko": "application/x-object",
"lnk": "application/x-ms-shortcut",
"lua": "text/x-lua",
"M": "text/x-objectivec",
"m": "text/x-objectivec",
"macho": "application/x-mach-binary",
"mm": "text/x-objectivec",
"md": "",
"o": "application/octet-stream",
"pe": "application/vnd.microsoft.portable-executable",
"php": "text/x-php",
"pl": "text/x-perl",
"pm": "text/x-script.perl-module",
Expand Down Expand Up @@ -209,7 +215,7 @@ func makeFileType(path string, ext string, mime string) *FileType {
return Path(".elf")
}

if strings.Contains(mime, "application") || strings.Contains(mime, "text/x-") || strings.Contains(mime, "text/x-") || strings.Contains(mime, "executable") {
if strings.Contains(mime, "application") || strings.Contains(mime, "text/x-") || strings.Contains(mime, "executable") {
return &FileType{
Ext: ext,
MIME: mime,
Expand Down
19 changes: 18 additions & 1 deletion pkg/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

"github.com/chainguard-dev/clog"
"github.com/chainguard-dev/malcontent/pkg/malcontent"
"github.com/chainguard-dev/malcontent/pkg/programkind"

yarax "github.com/VirusTotal/yara-x/go"
)
Expand Down Expand Up @@ -364,8 +365,20 @@ func TrimPrefixes(path string, prefixes []string) string {
return path
}

// fileMatchesRules checks the scanned file's type against a rule's defined filetypes.
func fileMatchesRule(meta []yarax.Metadata, ext string) bool {
for _, m := range meta {
if m.Identifier() == "filetypes" {
filetypes := strings.Split(fmt.Sprintf("%s", m.Value()), ",")
return slices.Contains(filetypes, ext)
}
}
// Rules without filetype metadata are universal
return true
}

//nolint:cyclop // ignore complexity of 64
func Generate(ctx context.Context, path string, mrs *yarax.ScanResults, c malcontent.Config, expath string, _ *clog.Logger, fc []byte) (*malcontent.FileReport, error) {
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) {
if ctx.Err() != nil {
return &malcontent.FileReport{}, ctx.Err()
}
Expand Down Expand Up @@ -425,6 +438,10 @@ func Generate(ctx context.Context, path string, mrs *yarax.ScanResults, c malcon
ignoreMalcontent = true
}

if !fileMatchesRule(m.Metadata(), kind.Ext) {
continue
}

override := slices.Contains(m.Tags(), "override")

risk = behaviorRisk(m.Namespace(), m.Identifier(), m.Tags())
Expand Down
1 change: 1 addition & 0 deletions rules/anti-behavior/LD_DEBUG.yara
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
rule env_LD_DEBUG: medium {
meta:
description = "may check if dynamic linker debugging is enabled"
filetypes = "elf,macho"

strings:
$val = "LD_DEBUG" fullword
Expand Down
1 change: 1 addition & 0 deletions rules/anti-behavior/LD_PROFILE.yara
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
rule env_LD_PROFILE: medium {
meta:
description = "may check if dynamic linker profiling is enabled"
filetypes = "elf,macho"

strings:
$val = "LD_PROFILE" fullword
Expand Down
3 changes: 3 additions & 0 deletions rules/anti-behavior/anti-debugger.yara
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
rule win_debugger_present: medium windows {
meta:
description = "Detects if process is being executed within a debugger"
filetypes = "exe,pe,ps1"

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

strings:
$cpu_pfp = "IsProcessorFeaturePresent"
Expand All @@ -27,6 +29,7 @@ rule win_debugger_or_vm: medium windows {
rule multiple_linux_methods: high linux {
meta:
description = "possible debugger detection across multiple methods"
filetypes = "elf"

strings:
$ld_profile = "LD_PROFILE" fullword
Expand Down
3 changes: 3 additions & 0 deletions rules/anti-behavior/process-check.yara
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
rule activity_monitor_checker: high macos {
meta:
description = "checks if 'Activity Monitor' is running"
filetypes = "macho"

strings:
$ps = "ps" fullword
Expand All @@ -16,6 +17,7 @@ rule activity_monitor_checker: high macos {
rule linux_monitors: high linux {
meta:
description = "checks if various process monitors are running"
filetypes = "elf"

strings:
$pgrep = "pgrep" fullword
Expand Down Expand Up @@ -45,6 +47,7 @@ rule linux_monitors: high linux {
rule anti_rootkit_hunter: high linux {
meta:
description = "checks if rootkit detectors are running"
filetypes = "elf"

strings:
$proc = "/proc/"
Expand Down
4 changes: 4 additions & 0 deletions rules/anti-behavior/random_behavior.yara
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ private rule random_behavior_pythonSetup {
rule setuptools_random: critical {
meta:
description = "Python library installer that exhibits random behavior"
filetypes = "py"

strings:
$ref = "import random"
Expand All @@ -32,6 +33,7 @@ rule setuptools_random: critical {
rule java_random: low {
meta:
description = "exhibits random behavior"
filetypes = "java"

strings:
$ref = "java/util/Random"
Expand All @@ -43,6 +45,7 @@ rule java_random: low {
rule go_rand: medium {
meta:
description = "exhibits random behavior"
filetypes = "go"

strings:
$ref = "math/rand"
Expand All @@ -54,6 +57,7 @@ rule go_rand: medium {
rule rand_call: medium {
meta:
description = "exhibits random behavior"
filetypes = "c,pl,php"

strings:
$ref = "rand()"
Expand Down
6 changes: 6 additions & 0 deletions rules/anti-static/base64/eval.yara
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "math"
rule eval_base64: high {
meta:
description = "Evaluates base64 content"
filetypes = "js,ts"

strings:
$eval = /eval\(.{0,256}base64/
Expand All @@ -14,6 +15,7 @@ rule eval_base64: high {
rule ruby_eval_base64_decode: critical {
meta:
description = "Evaluates base64 content"
filetypes = "rb"

strings:
$eval_base64_decode = "eval(Base64."
Expand All @@ -25,6 +27,7 @@ rule ruby_eval_base64_decode: critical {
rule ruby_eval_near_enough: high {
meta:
description = "Evaluates base64 content"
filetypes = "rb"

strings:
$eval = "eval("
Expand All @@ -37,6 +40,7 @@ rule ruby_eval_near_enough: high {
rule ruby_eval2_near_enough: high {
meta:
description = "Evaluates base64 content"
filetypes = "rb"

strings:
$eval = "eval("
Expand All @@ -49,6 +53,7 @@ rule ruby_eval2_near_enough: high {
rule python_exec_near_enough_base64: high {
meta:
description = "Likely executes base64 content"
filetypes = "py"

strings:
$exec = "exec("
Expand All @@ -61,6 +66,7 @@ rule python_exec_near_enough_base64: high {
rule python_base64_exec: critical {
meta:
description = "executes compressed base64 content"
filetypes = "py"

strings:
$dec_b64decode_exec = /.{0,8}\.decompress\(.{0,96}\.b64decode\(.{0,64}\Wexec\(.{0,16}/
Expand Down
4 changes: 4 additions & 0 deletions rules/anti-static/base64/exec.yara
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ rule base64_suspicious_commands: critical {
rule base64_exec: critical {
meta:
description = "executes base64 encoded commands"
filetypes = "py"

strings:
$os_system = /os\.system\(b64[\"\'\(\)\w\=]{3,96}/ fullword
Expand All @@ -61,6 +62,7 @@ rule base64_exec: critical {
rule echo_decode_bash: critical {
meta:
description = "executes base64 encoded shell commands"
filetypes = "bash,sh,zsh"

strings:
$pipe = /base64 {0,2}(-d|--decode) {0,2}\| {0,2}(bash|zsh|sh)/ fullword
Expand All @@ -75,6 +77,7 @@ import "math"
rule echo_decode_bash_probable: high {
meta:
description = "likely pipes base64 into a shell"
filetypes = "bash,sh,zsh"

strings:
$decode = /base64 {0,2}(-d|--decode)/ fullword
Expand All @@ -87,6 +90,7 @@ rule echo_decode_bash_probable: high {
rule ruby_system_near_enough: critical {
meta:
description = "Executes commands from base64 content"
filetypes = "rb"

strings:
$system = /system\(["'\w\)]{0,16}/
Expand Down
3 changes: 3 additions & 0 deletions rules/anti-static/base64/function_names.yara
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
rule base64_php_functions: medium {
meta:
description = "References PHP functions in base64 form"
filetypes = "php"

strings:
$php = "<?php"
Expand Down Expand Up @@ -67,6 +68,7 @@ rule base64_php_functions: medium {
rule base64_php_functions_multiple: critical {
meta:
description = "References multiple PHP functions in base64 form"
filetypes = "php"

strings:
$php = "<?php"
Expand Down Expand Up @@ -133,6 +135,7 @@ rule base64_php_functions_multiple: critical {
rule base64_python_functions: critical {
meta:
description = "contains base64 Python code"
filetypes = "py"

strings:
$f_exec = "exec(" base64
Expand Down
2 changes: 2 additions & 0 deletions rules/anti-static/base64/shell.yara
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
rule base64_shell: high {
meta:
description = "Contains base64 shell script"
filetypes = "bash,sh,zsh"

strings:
$if = "aWYgW1sg"
Expand All @@ -14,6 +15,7 @@ rule base64_shell: high {
rule base64_shell_base64: critical {
meta:
description = "Contains base64 encoded base64 command"
filetypes = "bash,sh,zsh"

strings:
$base64 = "YmFzZTY0IC"
Expand Down
1 change: 1 addition & 0 deletions rules/anti-static/elf/base64.yara
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ rule contains_base64_elf: high {
rule elf_contains_base64_elf: critical {
meta:
description = "ELF binary contains base64 ELF binary"
filetypes = "elf"

strings:
$elf_head = "f0VMRgI"
Expand Down
Loading
Loading