Skip to content

Commit

Permalink
Improve malicious Javascript detection (chainguard-dev#572)
Browse files Browse the repository at this point in the history
* Improve malicious Javascript detection

* update testdata

* alert tuning to reduce false positives

* update testdata
  • Loading branch information
tstromberg authored Nov 3, 2024
1 parent 1a9783b commit 521a7e7
Show file tree
Hide file tree
Showing 105 changed files with 662 additions and 205 deletions.
5 changes: 2 additions & 3 deletions pkg/action/testdata/scan_archive
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# testdata/apko_nested.tar.gz ∴ /apko_0.13.2_linux_arm64/apko: high
# testdata/apko_nested.tar.gz ∴ /apko_0.13.2_linux_arm64/apko: medium
c2/addr/ip_port: medium
c2/server_address: medium
c2/tool_transfer/shell: medium
collect/archives/zip: medium
credential/keychain: medium
credential/password: low
Expand Down Expand Up @@ -35,7 +34,7 @@ discover/user/USER: low
discover/user/name_get: medium
evasion/bypass_security/linux/se: medium
evasion/hidden_files/hidden: medium
evasion/hide_artifacts/pivot_root: high
evasion/hide_artifacts/pivot_root: medium
exec/plugin: low
exec/program: medium
exec/shell/background_sleep: medium
Expand Down
1 change: 1 addition & 0 deletions pkg/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ var rulesWithWarnings = map[string]bool{
"osascript_quitter": true,
"exfil_libcurl_elf": true,
"small_opaque_archaic_gcc": true,
"elf_hardcoded_ip": true,
}

func Recursive(ctx context.Context, fss []fs.FS) (*yara.Rules, error) {
Expand Down
2 changes: 2 additions & 0 deletions pkg/programkind/programkind.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ func File(path string) (*FileType, error) {
return Path(".php"), nil
case strings.HasPrefix(s, "import "):
return Path(".py"), nil
case strings.Contains(s, " = require("):
return Path(".js"), nil
case strings.HasPrefix(s, "#!/bin/ash") ||
strings.HasPrefix(s, "#!/bin/bash") ||
strings.HasPrefix(s, "#!/bin/fish") ||
Expand Down
33 changes: 33 additions & 0 deletions rules/anti-static/obfuscation/js/bitwise.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
rule unsigned_bitwise_math: medium {
meta:
description = "uses unsigned bitwise math"
ref = "https://www.reversinglabs.com/blog/python-downloader-highlights-noise-problem-in-open-source-threat-detection"
filetypes = "javascript"

strings:
$function = "function("
$charAt = /charAt\([a-zA-Z]/
$left = /[a-z]\>\>\>\d{1,3}/
$right = /[a-z]\>\>\>\d{1,3}/
condition:
filesize < 5MB and $function and $charAt and (#left > 5 or #right > 5)
}

rule unsigned_bitwise_math_excess: high {
meta:
description = "uses an excessive amount of unsigned bitwise math"
ref = "https://www.reversinglabs.com/blog/python-downloader-highlights-noise-problem-in-open-source-threat-detection"
filetypes = "javascript"

strings:
$function = "function("
$charAt = /charAt\([a-zA-Z]/
$left = /[a-z]\>\>\>\d{1,3}/
$right = /[a-z]\>\>\>\d{1,3}/
condition:
filesize < 5MB and $function and $charAt and (#left > 50 or #right > 50)
}
4 changes: 2 additions & 2 deletions rules/anti-static/obfuscation/js/char_codes.yara
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "math"

rule child_process: high {
rule character_obfuscation: medium {
meta:
description = "obfuscated javascript that relies on character manipulation"
filetypes = "javascript"
Expand All @@ -19,5 +19,5 @@ rule child_process: high {
$return = "{return"
condition:
filesize < 128KB and all of them
filesize < 4MB and all of them
}
16 changes: 15 additions & 1 deletion rules/anti-static/obfuscation/js/char_to_int.yara
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
rule js_char_code_at_substitution: high {
meta:
description = "converts strings into integers and contains a substitution map"
description = "converts integers into strings and contains a substitution map"
filetypes = "javascript"

strings:
Expand All @@ -10,3 +10,17 @@ rule js_char_code_at_substitution: high {
condition:
filesize < 256KB and all of them
}

rule chartBitwise: high {
meta:
description = "converts manipulated numbers into characters"
filetypes = "javascript"

strings:
$function = "function("
$c_left = /charAt\([a-z]\>\>\>\d.{0,8}/
$c_remainder = /charAt\(\w%\w.{0,8}/
condition:
filesize < 5MB and $function and any of ($c*)
}
32 changes: 32 additions & 0 deletions rules/anti-static/obfuscation/js/ebe.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
rule ebe: critical {
meta:
description = "highly obfuscated javascript (eBe)"
filetypes = "javascript"

strings:
$function = "function("
$charCodeAt = "charCodeAt"
$ref = /eBe\(-\d{1,3}\)/
condition:
filesize < 5MB and $function and $charCodeAt and #ref > 10
}

rule ebe_generic: high {
meta:
description = "highly obfuscated javascript"
filetypes = "javascript"

strings:
$function = "function("
$charCodeAt = "charCodeAt"
$ref = /\w\[\w{1,3}\(\d{1,3}\)\]=\w{1,3}\(\d{1,3}\),e\[\w{1,3}\(\d{1,3}\)\]/
$ref2 = /\w\[\w{1,3}\(\d{1,3}\)\]\&\w{1,3}\(\d{1,3}\)\),\w\[\w{1,3}\(\d{1,3}\)\]/
$ref3 = /\>\w{1,3}\(\d{1,3}\)\);\w\[\w{1,3}\(\d{1,3}\)\]\=/
condition:
filesize < 5MB and #function and $charCodeAt and (#ref > 5 or #ref2 > 5 or #ref3 > 5)
}

13 changes: 13 additions & 0 deletions rules/anti-static/obfuscation/js/int_to_char.yara
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,16 @@ rule js_char_code_at: medium {
condition:
filesize < 16KB and any of them
}

rule charCodeAtIncrement: high {
meta:
description = "converts incremented numbers into characters"
filetypes = "javascript"

strings:
$function = "function("
$increment = /charCodeAt\(\+\+\w{0,4}\)/
condition:
filesize < 4MB and $function and #increment > 1
}
13 changes: 13 additions & 0 deletions rules/anti-static/obfuscation/js/power.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
rule over_powered_arrays: high {
meta:
description = "uses many powered array elements (>25)"
filetypes = "javascript"

strings:
$function = /function\(\w,/
$charAt = /charAt\([a-zA-Z]/
$power_array = /\w\[\d{1,4}\]\^\w\[\d{1,4}\]/
condition:
filesize < 5MB and $function and $charAt and #power_array > 25
}
8 changes: 5 additions & 3 deletions rules/anti-static/obfuscation/php/unusual_include.yara
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ rule php_suppressed_include: high {
hash_2024_Deobfuscated_r57Shell_0fa5df7bbf035cb307867a5b5e783abfb0158976 = "f1e1d38c1f0461d2c1eea27eb1d6dcee966826bc1a2d3e34850cb0acc17e72ac"

strings:
$php = "<?php"
$include = /@\s*include\s*/
$php = "<?php"
$include = /@\s*include\s*/
$not_snippet = "snippet" fullword
$not_copyright = "copyright" fullword
condition:
filesize < 5242880 and all of them
filesize < 5242880 and $php and $include and none of ($not*)
}
4 changes: 3 additions & 1 deletion rules/anti-static/xor/xor-commands.yara
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ rule xor_commands: high {
$b_base642 = "base64" xor(33-255)
$b_eval2 = "eval(" xor(33-255)
$not_password_list = "qwer1234"
condition:
any of ($b_*)
any of ($b_*) and not ($b_eval and $not_password_list)
}
30 changes: 26 additions & 4 deletions rules/c2/addr/ip.yara
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
rule hardcoded_ip: medium {
meta:
description = "hardcoded IP address"
hash_2023_Downloads_016a = "016a1a4fe3e9d57ab0b2a11e37ad94cc922290d2499b8d96957c3ddbdc516d74"
hash_2024_Downloads_0fa8a2e98ba17799d559464ab70cce2432f0adae550924e83d3a5a18fe1a9fc8 = "503fcf8b03f89483c0335c2a7637670c8dea59e21c209ab8e12a6c74f70c7f38"
hash_2023_Downloads_311c = "311c93575efd4eeeb9c6674d0ab8de263b72a8fb060d04450daccc78ec095151"
description = "hardcoded IP address"
hash_2023_Downloads_016a = "016a1a4fe3e9d57ab0b2a11e37ad94cc922290d2499b8d96957c3ddbdc516d74"
hash_2024_Downloads_0fa8 = "503fcf8b03f89483c0335c2a7637670c8dea59e21c209ab8e12a6c74f70c7f38"
hash_2023_Downloads_311c = "311c93575efd4eeeb9c6674d0ab8de263b72a8fb060d04450daccc78ec095151"

strings:
$ipv4 = /([1-9][0-9]{1,2}\.){3}[1-9][0-9]{1,2}/ fullword

Check warning on line 9 in rules/c2/addr/ip.yara

View check run for this annotation

VirusTotal YARA-CI / Rules Analysis

rules/c2/addr/ip.yara#L9

rule "hardcoded_ip": string "$ipv4" may slow down scanning
Expand All @@ -19,3 +19,25 @@ rule hardcoded_ip: medium {
condition:
1 of ($ip*) and none of ($not*)
}

rule elf_hardcoded_ip: high {
meta:
description = "hardcoded IP address"
hash_2023_Downloads_016a = "016a1a4fe3e9d57ab0b2a11e37ad94cc922290d2499b8d96957c3ddbdc516d74"
hash_2024_Downloads_0fa8 = "503fcf8b03f89483c0335c2a7637670c8dea59e21c209ab8e12a6c74f70c7f38"
hash_2023_Downloads_311c = "311c93575efd4eeeb9c6674d0ab8de263b72a8fb060d04450daccc78ec095151"

strings:
$ipv4 = /([1-9][0-9]{1,2}\.){3}[1-9][0-9]{1,2}/ fullword

Check warning on line 31 in rules/c2/addr/ip.yara

View check run for this annotation

VirusTotal YARA-CI / Rules Analysis

rules/c2/addr/ip.yara#L31

rule "elf_hardcoded_ip": string "$ipv4" may slow down scanning
$not_localhost = "127.0.0.1"
$not_broadcast = "255.255.255.255"
$not_upnp = "239.255.255.250"
$not_weirdo = "635.100.12.38"
$not_incr = "10.11.12.13"
$not_169 = "169.254.169.254"
$not_spyder = "/search/spider"
$not_ruby = "210.251.121.214"
condition:
filesize < 4MB and uint32(0) == 1179403647 and 1 of ($ip*) and none of ($not*)
}
1 change: 1 addition & 0 deletions rules/c2/addr/ip_port.yara
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ rule hardcoded_ip_port: high {
$not_vnc = "10.10.10.10:5900"
$not_azure_pgsql = "20.66.25.58:5432"
$not_wireguard = "127.212.121.99:999"
$not_minio = "172.16.34.31:9000"
$not_test = "def test_" fullword
condition:
Expand Down
44 changes: 34 additions & 10 deletions rules/c2/addr/server.yara
Original file line number Diff line number Diff line change
@@ -1,15 +1,39 @@
rule server_addr: high {
rule server_addr: medium {
meta:
description = "may execute a shell and communicate with a server"

strings:
$serverAddr = "serverAddr"
$server_addr = "server_addr"
$exec = "exec"
$sh = "sh" fullword
$sh_bash = "bash" fullword
$sh_zsh = "zsh" fullword
$sh_script = "ShellScript"
$sh_exec = "ExecShell"
$sh_cmd = "cmd.exe"
$serverAddr = "serverAddr"
$server_addr = "server_addr"
$exec = "exec"
$sh = "/bin/sh" fullword
$sh_bash = "/bin/bash" fullword
$sh_zsh = "/bin/zsh" fullword
$sh_script = "ShellScript"
$sh_exec = "ExecShell"
$sh_cmd = "cmd.exe"
$sh_powershell = "powershell.exe"
condition:
filesize < 10MB and any of ($server*) and $exec and any of ($sh*)
}

rule server_addr_small: high {
meta:
description = "may execute a shell and communicate with a server"

strings:
$serverAddr = "serverAddr"
$server_addr = "server_addr"
$exec = "exec"
$sh = "/bin/sh" fullword
$sh_bash = "/bin/bash" fullword
$sh_zsh = "/bin/zsh" fullword
$sh_script = "ShellScript"
$sh_exec = "ExecShell"
$sh_cmd = "cmd.exe"
$sh_powershell = "powershell.exe"
condition:
filesize < 128KB and any of ($server*) and $exec and any of ($sh*)
}
8 changes: 4 additions & 4 deletions rules/c2/addr/url-unusual.yara
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
rule unusual_nodename {
rule unusual_nodename: medium {
meta:
description = "Contains HTTP hostname with a long node name"

strings:
$ref = /https*:\/\/\w{16,}\//
condition:
$ref
filesize < 5MB and $ref
}

rule exotic_tld {
rule exotic_tld: high {
meta:
description = "Contains HTTP hostname with unusual top-level domain"

Expand All @@ -21,5 +21,5 @@ rule exotic_tld {
$not_eol = "endoflife.date"
condition:
any of ($http*) and none of ($not_*)
filesize < 10MB and any of ($http*) and none of ($not_*)
}
12 changes: 12 additions & 0 deletions rules/c2/discovery/ethereum.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
rule ethereum_c2: high {
meta:
description = "may use Ethereum to discover command and control server"

strings:
$axios = "axios"
$ethers = /ethers\.Contract\('0x\w{8,64}\'/
$getstring = ".getString("
condition:
filesize < 128KB and all of them
}
19 changes: 19 additions & 0 deletions rules/c2/tool_transfer/777_dropper.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
rule chmod_777_dropper: critical {
meta:
description = "transfers program, uses dangerous permissions, and possibly runs a binary"
filetypes = "macho,elf"

strings:
$chmod = /chmod [\-\w ]{0,3}777 [ \$\@\w\/\.]{0,64}/
$t_wget = "wget" fullword
$t_curl = "curl" fullword
$t_tftp = "tftp" fullword
$o_dotslash = /\.\/[\.\$\w]{0,16}/
$o_rm = /rm -[rR]{0,1}f/
$o_tmp = "/tmp/"
$o_dev = "/dev/"
condition:
filesize < 1KB and $chmod and any of ($t*) and any of ($o*)
}
13 changes: 8 additions & 5 deletions rules/c2/tool_transfer/js.yara
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ rule javascript_dropper: critical {
description = "Javascript dropper"

strings:
$lib_http = /require\(['"]https{0,1}['"]\);/
$lib_fs = /require\(['"]fs['"]\);/
$lib_child_process = /require\(['"]child_process['"]\);/
$lh = /require\(['"]https{0,1}['"]\)/
$lh_axios = /require\(['"]axios{0,1}['"]\)/
$lib_fs = /require\(['"]fs['"]\)/
$lib_child_process = /require\(['"]child_process['"]\)/
$http = "http://"
$https = "https://"
$temp = "TEMP"
$dir_temp = "TEMP"
$dir_home = "os.homedir"
$other_unlink = ".unlink"
$other_create = ".createWriteStream"
$other_http = "http.get"
$other_method = "method: 'GET'"
condition:
filesize < 2KB and all of ($lib*) and $temp and any of ($http*) and 2 of ($other*)
filesize < 3KB and all of ($lib*) and any of ($lh*) and any of ($dir*) and any of ($http*) and 2 of ($other*)
}
Loading

0 comments on commit 521a7e7

Please sign in to comment.