Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve results scanning for Linux malware #608

Merged
merged 7 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/action/testdata/scan_archive
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# testdata/apko_nested.tar.gz ∴ /apko_0.13.2_linux_arm64/apko: medium
c2/addr/ip: medium
c2/server_address: medium
c2/addr/server: medium
collect/archives/zip: medium
credential/keychain: medium
credential/password: low
Expand Down Expand Up @@ -32,7 +32,7 @@ discover/user/HOME: low
discover/user/USER: low
discover/user/name_get: medium
evasion/bypass_security/linux/se: medium
evasion/hidden_paths/hidden: medium
evasion/file/prefix: medium
evasion/hide_artifacts/pivot_root: medium
exec/plugin: low
exec/program: medium
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "math"
import "elf"

rule obfuscated_elf: high linux {
meta:
Expand Down Expand Up @@ -27,21 +27,5 @@ rule obfuscated_elf: high linux {
$debuglink = ".gnu_debuglink" fullword

condition:
uint32(0) == 1179403647 and none of them
}

rule high_entropy_header: high {
meta:
description = "high entropy ELF header (>7)"
hash_2023_UPX_0c25 = "0c25a05bdddc144fbf1ffa29372481b50ec6464592fdfb7dec95d9e1c6101d0d"
hash_2023_UPX_5a59 = "5a5960ccd31bba5d47d46599e4f10e455b74f45dad6bc291ae448cef8d1b0a59"
hash_2023_FontOnLake_38B09D690FAFE81E964CBD45EC7CF20DCB296B4D_elf = "f155fafa36d1094433045633741df98bbbc1153997b3577c3fa337cc525713c0"

strings:
$not_pyinst = "pyi-bootloader-ignore-signals"
$not_go = "syscall_linux.go"
$not_go2 = "vdso_linux.go"

condition:
uint32(0) == 1179403647 and math.entropy(1200, 4096) > 7 and none of ($not*)
filesize > 512 and elf.type == elf.ET_EXEC and uint32(0) == 1179403647 and none of them
}
30 changes: 30 additions & 0 deletions rules/anti-static/elf/entropy.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import "math"

private rule normal_elf {
condition:
filesize < 64MB and uint32(0) == 1179403647
}

private rule small_elf {
condition:
filesize < 400KB and uint32(0) == 1179403647
}

rule normal_elf_high_entropy_7: medium {
meta:
description = "higher entropy ELF binary (>7.1)"

condition:
normal_elf and math.entropy(1, filesize) >= 7.1
}

rule normal_elf_high_entropy_7_4: high {
meta:
description = "high entropy ELF binary (>7.4)"

strings:
$not_whirlpool = "libgcrypt-grub/cipher/whirlpool.c"

condition:
normal_elf and math.entropy(1, filesize) >= 7.4 and none of ($not*)
}
18 changes: 18 additions & 0 deletions rules/anti-static/elf/header.yara
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import "elf"
import "math"

rule single_load_rwe: critical {
meta:
Expand Down Expand Up @@ -38,3 +39,20 @@ rule fake_dynamic_symbols: critical {
condition:
elf.type == elf.ET_EXEC and elf.entry_point < filesize and elf.number_of_sections > 0 and elf.dynamic_section_entries > 0 and for any i in (0..elf.dynamic_section_entries): (elf.dynamic[i].type == elf.DT_SYMTAB and not (for any j in (0..elf.number_of_sections): (elf.sections[j].type == elf.SHT_DYNSYM and for any k in (0..elf.number_of_segments): ((elf.segments[k].virtual_address <= elf.dynamic[i].val) and ((elf.segments[k].virtual_address + elf.segments[k].file_size) >= elf.dynamic[i].val) and (elf.segments[k].offset + (elf.dynamic[i].val - elf.segments[k].virtual_address)) == elf.sections[j].offset))))
}

rule high_entropy_header: high {
meta:
description = "high entropy ELF header (>7)"
hash_2023_UPX_0c25 = "0c25a05bdddc144fbf1ffa29372481b50ec6464592fdfb7dec95d9e1c6101d0d"
hash_2023_UPX_5a59 = "5a5960ccd31bba5d47d46599e4f10e455b74f45dad6bc291ae448cef8d1b0a59"
hash_2023_FontOnLake_38B09D690FAFE81E964CBD45EC7CF20DCB296B4D_elf = "f155fafa36d1094433045633741df98bbbc1153997b3577c3fa337cc525713c0"

strings:
$not_pyinst = "pyi-bootloader-ignore-signals"
$not_go = "syscall_linux.go"
$not_go2 = "vdso_linux.go"
$not_module = ".module_license" fullword

condition:
uint32(0) == 1179403647 and elf.type == elf.ET_EXEC and math.entropy(1200, 4096) > 7 and none of ($not*)
}
12 changes: 12 additions & 0 deletions rules/anti-static/elf/tiny.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import "elf"

rule impossibly_small_elf_program: high {
meta:
description = "ELF binary is unusually small"

strings:
$not_hello_c = "hello.c"

condition:
filesize < 8192 and filesize > 900 and uint32(0) == 1179403647 and elf.type == elf.ET_EXEC and none of ($not*)
}
26 changes: 26 additions & 0 deletions rules/anti-static/macho/entropy.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import "math"

private rule smaller_macho {
condition:
filesize < 64MB and (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962)
}

rule high_entropy_7_2: medium {
meta:
description = "higher entropy binary (>7.2)"

condition:
smaller_macho and math.entropy(1, filesize) >= 7.2
}

rule high_entropy_7_9: high {
meta:
description = "high entropy binary (>7.9)"

strings:
// prevent bazel false positive
$bin_java = "bin/java"

condition:
smaller_macho and math.entropy(1, filesize) >= 7.9 and not $bin_java
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
import "elf"

rule impossibly_small_elf_program: high {
meta:
description = "ELF binary is unusually small"

condition:
filesize < 8192 and uint32(0) == 1179403647 and elf.type == elf.ET_EXEC
}

rule impossibly_small_macho_program: medium {
meta:
description = "machO binary is unusually small"
Expand Down
24 changes: 16 additions & 8 deletions rules/anti-static/obfuscation/bitwise.yara
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,22 @@ rule excessive_bitwise_math: high {
hash_2023_aiohttpp_0_1_setup = "cfa4137756f7e8243e7c7edc7cb0b431a2f4c9fa401f2570f1b960dbc86ca7c6"

strings:
$x = /\-{0,1}[\da-z]{1,8} \<\< \-{0,1}\d{1,8}/
$not_Sodium = "Sodium_Core"
$not_SHA512 = "SHA512"
$not_SHA256 = "SHA256"
$not_MD4 = "MD4"
$not_algbase = "algbase" fullword
$not_jslint = "jslint bitwise"
$not_include = "#define "
$x = /\-{0,1}[\da-z]{1,8} \<\< \-{0,1}\d{1,8}/
$not_Sodium = "Sodium_Core"
$not_SHA512 = "SHA512"
$not_SHA256 = "SHA256"
$not_MD4 = "MD4"
$not_algbase = "algbase" fullword
$not_jslint = "jslint bitwise"
$not_include = "#define "
$not_bitwise = "bitwise" fullword
$not_bitmasks = "bitmasks" fullword
$not_ckbcomp = "ckbcomp" fullword
$not_bit_test = "bits_test" fullword
$not_testing = "*testing.T"
$not_effective_bits = "effective bits"
$not_bit_offsets = "bit offsets"
$not_uuid = "uuid" fullword

condition:
filesize < 192KB and #x > 64 and none of ($not*)
Expand Down
15 changes: 8 additions & 7 deletions rules/anti-static/obfuscation/hex.yara
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ rule hex_parse_base64_high: high {
hash_1985_package_index = "8d4daa082c46bfdef3d85a6b5e29a53ae4f45197028452de38b729d76d3714d1"

strings:
$lang_node = /Buffer\.from\(\w{0,16}, {0,2}'hex'\)/
$lang_python = /\.unhexlify\(/
$b_base64 = "base64"
$b_b64decode = "b64decode"
$not_sha256 = "sha256" fullword
$not_sha512 = "sha512" fullword
$not_algorithms = "algorithms" fullword
$lang_node = /Buffer\.from\(\w{0,16}, {0,2}'hex'\)/
$lang_python = /\.unhexlify\(/
$b_base64 = "base64"
$b_b64decode = "b64decode"
$not_sha256 = "sha256" fullword
$not_sha512 = "sha512" fullword
$not_algorithms = "algorithms" fullword
$not_python_base64 = "return binascii.unhexlify(s)"

condition:
filesize < 32KB and any of ($lang*) and any of ($b*) and none of ($not*)
Expand Down
9 changes: 7 additions & 2 deletions rules/anti-static/obfuscation/python.yara
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,11 @@ rule fernet_base64: high {
$o6 = "exec("
$o7 = "eval("

$not_utils = "from cryptography import utils"
$not_fernet_itself = "class Fernet"

condition:
filesize < 2MB and any of ($fernet*) and any of ($bdecode*) and any of ($o*)
filesize < 2MB and any of ($fernet*) and any of ($bdecode*) and any of ($o*) and none of ($not*)
}

rule python_long_hex: medium {
Expand Down Expand Up @@ -261,8 +264,10 @@ rule python_hex_decimal: high {

$trash = /\\x{0,1}\d{1,3}\\/

$not_testing_t = "*testing.T" fullword

condition:
filesize < 1MB and any of ($f*) and #trash in (filesize - 1024..filesize) > 100
filesize < 1MB and any of ($f*) and #trash in (filesize - 1024..filesize) > 100 and none of ($not*)
}

rule dumb_int_compares: high {
Expand Down
5 changes: 3 additions & 2 deletions rules/anti-static/packer/cx_freeze.yara
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ rule cxFreeze_Python_executable: high {
hash_2023_MacStealer_weed = "6a4f8b65a568a779801b72bce215036bea298e2c08ec54906bb3ebbe5c16c712"

strings:
$cxfreeze = "cx_Freeze"
$cxfreeze = "cx_Freeze"
$not_importlib = "tool like cx_Freeze"

condition:
filesize < 10485760 and $cxfreeze
filesize < 10485760 and $cxfreeze and none of ($not*)
}
27 changes: 0 additions & 27 deletions rules/anti-static/packer/high_entropy.yara

This file was deleted.

29 changes: 17 additions & 12 deletions rules/c2/addr/ip.yara
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ rule elf_hardcoded_ip: high {

strings:
// stricter version of what's above: excludes 255.* and *.0.* *.1.*, and 8.* (likely Google)
$sus_ipv4 = /((25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[2345679])\.){3}(25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[2-9])/ fullword
$not_version = /((25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[2-9])\.){3}(25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[2-9])[\.\-]/
$not_incr = "10.11.12.13"
$not_169 = "169.254.169.254"
$not_spyder = "/search/spider"
$not_ruby = "210.251.121.214"
$not_1_2_3_4 = "1.2.3.4"
$not_root_servers_h = "128.63.2.53"
$not_root_servers_i = "192.36.148.17"
$sus_ipv4 = /((25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[2345679])\.){3}(25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[2-9])/ fullword
$not_version = /((25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[2-9])\.){3}(25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[2-9])[\.\-]/
$not_incr = "10.11.12.13"
$not_169 = "169.254.169.254"
$not_spyder = "/search/spider"
$not_ruby = "210.251.121.214"
$not_1_2_3_4 = "1.2.3.4"
$not_root_servers_h = "128.63.2.53"
$not_root_servers_i = "192.36.148.17"
$not_123456789 = "123.45.67.89"
$not_libebt_among_init = "libebt_among_init"

condition:
filesize < 12MB and uint32(0) == 1179403647 and 1 of ($sus_ip*) and none of ($not*)
Expand Down Expand Up @@ -73,14 +75,17 @@ rule hardcoded_ip_port: high {

strings:
$ipv4 = /([1-9][0-9]{1,2}\.){3}[1-9][0-9]{1,2}:\d{2,5}/ fullword
$not_ssdp = "239.255.255.250:1900"
$not_ssdp = "239.255.255.250:"
$not_2181 = "10.101.203.230:2181"
$not_meta = "169.254.169.254:80"
$not_vnc = "10.10.10.10:5900"
$not_meta = "169.254.169.254:"
$not_vnc = "10.10.10.10:"
$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
$not_12 = "12.12.12.12:"
$not_21 = "21.21.21.21:"
$not_255 = "255.255.255.255:"

condition:
any of ($ip*) and none of ($not*)
Expand Down
28 changes: 14 additions & 14 deletions rules/c2/addr/server.yara
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
rule server_addr: medium {
rule server_address: medium {
meta:
description = "may execute a shell and communicate with a server"
description = "references a 'server address', possible C2 client"
hash_2024_Downloads_3105 = "31054fb826b57c362cc0f0dbc8af15b22c029c6b9abeeee9ba8d752f3ee17d7d"
hash_2023_Linux_Malware_Samples_450a = "450a7e35f13b57e15c8f4ce1fa23025a7c313931a394c40bd9f3325b981eb8a8"
hash_2023_Linux_Malware_Samples_458e = "458e3e66eff090bc5768779d5388336c8619a744f486962f5dfbf436a524ee04"

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"
$s_underscores = /\w{0,32}server_addr\w{0,32}/
$s_mixed = /\w{0,32}serverAddr\w{0,32}/
$s_url = "serverURL" fullword
$s_url2 = "serverUrl" fullword
$s_connect = /\w{0,32}ConnectServer\w{0,32}/

condition:
filesize < 10MB and any of ($server*) and $exec and any of ($sh*)
any of ($s*)
}

rule server_addr_small: high {
Expand All @@ -34,6 +32,8 @@ rule server_addr_small: high {
$sh_cmd = "cmd.exe"
$sh_powershell = "powershell.exe"

$hash_bang = "#!"

condition:
filesize < 128KB and any of ($server*) and $exec and any of ($sh*)
filesize < 1MB and any of ($server*) and $exec and any of ($sh*) and not $hash_bang in (0..3)
}
Loading