diff --git a/.github/workflows/style.yaml b/.github/workflows/style.yaml index 2bec77ad5..52e689c7c 100644 --- a/.github/workflows/style.yaml +++ b/.github/workflows/style.yaml @@ -31,14 +31,14 @@ jobs: - name: Install yara-x run: | - wget https://github.com/VirusTotal/yara-x/releases/download/v0.10.0/yara-x-v0.10.0-x86_64-unknown-linux-gnu.gzip -O yara-x.gzip - tar -xzvf yara-x.gzip && mv yr /usr/local/bin/ && rm yara-x.gzip + wget https://github.com/VirusTotal/yara-x/releases/download/v0.15.0/yara-x-v0.15.0-x86_64-unknown-linux-gnu.gz -O yara-x.gz + tar -xzvf yara-x.gz && mv yr /usr/local/bin/ && rm yara-x.gz - name: Verify yr installation run: | yr --version - name: Run yr compile run: | - yr compile rules/ + yr compile --path-as-namespace -w rules/ ret=$? if [[ $ret -ne 0 ]]; then echo "Rule compilation failed; address findings and commit the changes" diff --git a/pkg/compile/compile.go b/pkg/compile/compile.go index fcee83549..8668751f3 100644 --- a/pkg/compile/compile.go +++ b/pkg/compile/compile.go @@ -4,9 +4,11 @@ package compile import ( + "bytes" "context" "fmt" "io/fs" + "os" "path/filepath" "regexp" "strings" @@ -17,6 +19,11 @@ import ( yarax "github.com/VirusTotal/yara-x/go" ) +const ( + globalInclude = `include "rules/global/global.yara"` + globalPath = "rules/global/global.yara" +) + var FS = rules.FS // badRules are noisy 3rd party rules to silently disable. @@ -159,16 +166,57 @@ func removeRules(data []byte, rulesToRemove []string) []byte { return newlinePattern.ReplaceAll(modified, []byte("\n\n")) } +// findRoot locates the repository root on the fly. +func findRoot(start string) string { + current := start + for { + next := filepath.Join(current, "rules") + if _, err := os.Stat(next); err == nil { + return current + } + + parent := filepath.Dir(current) + if parent == current { + return "" + } + + current = parent + } +} + +// replaceGlobal updates the include string to reference the absolute path of rules/global/global.yara +// by default, the relative path is valid for local compilations and builds done from the root of the repository, +// but this is not valid for test files located in various directories. +func replaceGlobal(data []byte, path string) []byte { + modified := data + if bytes.Contains(data, []byte(globalInclude)) { + modified = bytes.Replace(data, []byte(globalInclude), []byte(fmt.Sprintf(`include "%s"`, path)), 1) + } + return modified +} + func Recursive(ctx context.Context, fss []fs.FS) (*yarax.Rules, error) { if ctx.Err() != nil { return nil, ctx.Err() } - yxc, err := yarax.NewCompiler(yarax.ConditionOptimization(true)) + yxc, err := yarax.NewCompiler(yarax.ConditionOptimization(true), yarax.EnableIncludes(true)) if err != nil { return nil, fmt.Errorf("yarax compiler: %w", err) } + // use the current working directory to determine the root path + // this only needs to be done once + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + abs, err := filepath.Abs(cwd) + if err != nil { + return nil, err + } + rootPath := findRoot(abs) + rulesToRemove := getRulesToRemove() for _, root := range fss { @@ -177,7 +225,11 @@ func Recursive(ctx context.Context, fss []fs.FS) (*yarax.Rules, error) { return err } - if !d.IsDir() && (filepath.Ext(path) == ".yara" || filepath.Ext(path) == ".yar") { + if d.IsDir() { + return nil + } + + if filepath.Ext(path) == ".yara" || filepath.Ext(path) == ".yar" { bs, err := fs.ReadFile(root, path) if err != nil { return fmt.Errorf("readfile: %w", err) @@ -185,6 +237,9 @@ func Recursive(ctx context.Context, fss []fs.FS) (*yarax.Rules, error) { bs = removeRules(bs, rulesToRemove) + globalAbs := filepath.Join(rootPath, globalPath) + bs = replaceGlobal(bs, globalAbs) + yxc.NewNamespace(path) if err := yxc.AddSource(string(bs), yarax.WithOrigin(path)); err != nil { return fmt.Errorf("failed to parse %s: %v", path, err) diff --git a/rules/anti-behavior/random_behavior.yara b/rules/anti-behavior/random_behavior.yara index 6e45dbe2f..36cd1a7a0 100644 --- a/rules/anti-behavior/random_behavior.yara +++ b/rules/anti-behavior/random_behavior.yara @@ -1,21 +1,6 @@ import "math" -private rule random_behavior_pythonSetup { - strings: - $if_distutils = /from distutils.core import .{0,32}setup/ - $if_setuptools = /from setuptools import .{0,32}setup/ - $i_setuptools = "import setuptools" - $setup = "setup(" - - $not_setup_example = ">>> setup(" - $not_setup_todict = "setup(**config.todict()" - $not_import_quoted = "\"from setuptools import setup" - $not_setup_quoted = "\"setup(name=" - $not_distutils = "from distutils.errors import" - - condition: - filesize < 128KB and $setup and any of ($i*) and none of ($not*) -} +include "rules/global/global.yara" rule setuptools_random: critical { meta: @@ -27,7 +12,7 @@ rule setuptools_random: critical { $not_easy_install = "pid = random.randint(0, sys.maxsize)" condition: - random_behavior_pythonSetup and $ref and none of ($not*) + global_python_setup and $ref and none of ($not*) } rule java_random: low { diff --git a/rules/anti-static/elf/entropy.yara b/rules/anti-static/elf/entropy.yara index 885270703..c81189ea4 100644 --- a/rules/anti-static/elf/entropy.yara +++ b/rules/anti-static/elf/entropy.yara @@ -1,14 +1,6 @@ import "math" -private rule normal_elf { - condition: - filesize < 64MB and uint32(0) == 1179403647 -} - -private rule small_elf { - condition: - filesize < 400KB and uint32(0) == 1179403647 -} +include "rules/global/global.yara" rule higher_elf_entropy_68: medium { meta: @@ -16,7 +8,7 @@ rule higher_elf_entropy_68: medium { filetypes = "elf" condition: - normal_elf and math.entropy(1, filesize) >= 6.95 + global_normal_elf and math.entropy(1, filesize) >= 6.95 } rule normal_elf_high_entropy_7_4: high { @@ -29,7 +21,7 @@ rule normal_elf_high_entropy_7_4: high { $not_bazel = "BazelLogHandler" condition: - filesize < 30MB and normal_elf and math.entropy(1, filesize) >= 7.4 and none of ($not*) + filesize < 30MB and global_normal_elf and math.entropy(1, filesize) >= 7.4 and none of ($not*) } rule normal_elf_high_entropy_footer_7_4: high { @@ -38,7 +30,7 @@ rule normal_elf_high_entropy_footer_7_4: high { filetypes = "elf" condition: - normal_elf and math.entropy(filesize - 8192, filesize) >= 7.4 + global_normal_elf and math.entropy(filesize - 8192, filesize) >= 7.4 } rule normal_elf_high_entropy_footer_7_4_rc4: high { @@ -51,5 +43,5 @@ rule normal_elf_high_entropy_footer_7_4_rc4: high { $cmp_r_x_256 = { 48 81 f? 00 01 00 00 } // cmp {rbx, rcx, …}, 256 condition: - filesize < 25MB and normal_elf and math.entropy(filesize - 8192, filesize) >= 7.4 and any of them + filesize < 25MB and global_normal_elf and math.entropy(filesize - 8192, filesize) >= 7.4 and any of them } diff --git a/rules/anti-static/macho/entropy.yara b/rules/anti-static/macho/entropy.yara index 6a821c505..e8e9589f7 100644 --- a/rules/anti-static/macho/entropy.yara +++ b/rules/anti-static/macho/entropy.yara @@ -1,9 +1,6 @@ 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) -} +include "rules/global/global.yara" rule higher_entropy_6_9: medium { meta: @@ -11,7 +8,7 @@ rule higher_entropy_6_9: medium { filetypes = "macho" condition: - smaller_macho and math.entropy(1, filesize) >= 6.9 + global_small_macho and math.entropy(1, filesize) >= 6.9 } rule high_entropy_7_2: high { @@ -24,5 +21,5 @@ rule high_entropy_7_2: high { $bin_java = "bin/java" condition: - smaller_macho and math.entropy(1, filesize) >= 7.2 and not $bin_java + global_small_macho and math.entropy(1, filesize) >= 7.2 and not $bin_java } diff --git a/rules/anti-static/macho/footer.yara b/rules/anti-static/macho/footer.yara index 5ee0acac5..b806d761f 100644 --- a/rules/anti-static/macho/footer.yara +++ b/rules/anti-static/macho/footer.yara @@ -1,9 +1,6 @@ import "math" -private rule anti_static_macho { - condition: - (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) -} +include "rules/global/global.yara" rule high_entropy_trailer: high { meta: @@ -15,5 +12,5 @@ rule high_entropy_trailer: high { $page_zero = "_PAGEZERO" condition: - filesize < 10MB and anti_static_macho and $page_zero and math.entropy(filesize - 1024, filesize - 1) >= 4 + filesize < 10MB and global_macho and $page_zero and math.entropy(filesize - 1024, filesize - 1) >= 4 } diff --git a/rules/anti-static/packer/aes.yara b/rules/anti-static/packer/aes.yara index 9f6c446d3..81445e1d5 100644 --- a/rules/anti-static/packer/aes.yara +++ b/rules/anti-static/packer/aes.yara @@ -1,10 +1,6 @@ import "math" -private rule smallBinary { - condition: - // matches ELF or machO binary - filesize > 1MB and filesize < 8MB and (uint32(0) == 1179403647 or uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962) -} +include "rules/global/global.yara" rule go_aes: high { meta: @@ -17,5 +13,5 @@ rule go_aes: high { $decrypt = "NewCFBDecrypter" condition: - smallBinary and math.entropy(1, filesize) >= 7 and all of them + global_small_binary and math.entropy(1, filesize) >= 7 and all of them } diff --git a/rules/anti-static/unmarshal/marshal.yara b/rules/anti-static/unmarshal/marshal.yara index e2da33b3d..619840366 100644 --- a/rules/anti-static/unmarshal/marshal.yara +++ b/rules/anti-static/unmarshal/marshal.yara @@ -1,15 +1,6 @@ import "math" -private rule pySetup { - strings: - $i_distutils = "from distutils.core import setup" - $i_setuptools = "setuptools" - $setup = "setup(" - $not_setuptools = "setuptools.command" - - condition: - filesize < 2097152 and $setup and any of ($i*) and none of ($not*) -} +include "rules/global/global.yara" rule unmarshal_py_marshal: medium { meta: @@ -29,5 +20,5 @@ rule setuptools_py_marshal: suspicious { filetypes = "py" condition: - pySetup and unmarshal_py_marshal + global_python_setup and unmarshal_py_marshal } diff --git a/rules/c2/addr/ip.yara b/rules/c2/addr/ip.yara index c51da388d..75baa9bd8 100644 --- a/rules/c2/addr/ip.yara +++ b/rules/c2/addr/ip.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule hardcoded_ip: medium { meta: description = "hardcoded IP address" @@ -19,11 +21,6 @@ rule hardcoded_ip: medium { filesize < 200MB and 1 of ($sus_ip*) and none of ($not*) } -private rule ip_elf_or_macho { - condition: - uint32(0) == 1179403647 or (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) -} - rule bin_hardcoded_ip: high { meta: description = "ELF with hardcoded IP address" @@ -48,7 +45,7 @@ rule bin_hardcoded_ip: high { $not_2345 = "23.45.67.89" condition: - filesize < 12MB and ip_elf_or_macho and 1 of ($sus_ip*) and none of ($not*) + filesize < 12MB and global_elf_or_macho and 1 of ($sus_ip*) and none of ($not*) } rule http_hardcoded_ip: high exfil { diff --git a/rules/c2/addr/url.yara b/rules/c2/addr/url.yara index 963e89ffc..a0db1d369 100644 --- a/rules/c2/addr/url.yara +++ b/rules/c2/addr/url.yara @@ -1,9 +1,6 @@ import "math" -private rule elf_or_macho { - condition: - uint32(0) == 1179403647 or (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) -} +include "rules/global/global.yara" rule unusual_nodename: medium { meta: @@ -85,7 +82,7 @@ rule binary_with_url: low { $ref = /https*:\/\/[\w\.\/]{8,160}[\/\w\=\&]{0,32}/ condition: - filesize < 150MB and elf_or_macho and $ref + filesize < 150MB and global_elf_or_macho and $ref } rule binary_url_with_question: high { @@ -102,7 +99,7 @@ rule binary_url_with_question: high { $not_mesibo = "https://api.mesibo.com/api.php?" condition: - filesize < 150MB and elf_or_macho and $ref and none of ($not*) + filesize < 150MB and global_elf_or_macho and $ref and none of ($not*) } rule script_url_with_question: high { diff --git a/rules/c2/tool_transfer/download.yara b/rules/c2/tool_transfer/download.yara index 13acfe6a4..ada9603c9 100644 --- a/rules/c2/tool_transfer/download.yara +++ b/rules/c2/tool_transfer/download.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule download_sites: high { meta: ref = "https://github.com/ditekshen/detection/blob/e6579590779f62cbe7f5e14b5be7d77b2280f516/yara/indicator_high.yar#L1001" @@ -113,12 +115,6 @@ rule http_archive_url: medium { any of ($ref*) and none of ($not*) } -private rule smallerBinary { - condition: - // matches ELF or machO binary - filesize < 10MB and (uint32(0) == 1179403647 or uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962) -} - rule http_archive_url_higher: high { meta: description = "accesses hardcoded archive file endpoint" @@ -129,5 +125,5 @@ rule http_archive_url_higher: high { $not_foo_bar = "http://foo/bar.tar" condition: - smallerBinary and any of ($ref*) and none of ($not*) + global_small_binary and any of ($ref*) and none of ($not*) } diff --git a/rules/c2/tool_transfer/macos.yara b/rules/c2/tool_transfer/macos.yara index 4c82c9b22..70c70683d 100644 --- a/rules/c2/tool_transfer/macos.yara +++ b/rules/c2/tool_transfer/macos.yara @@ -1,12 +1,4 @@ -private rule tool_transfer_macho { - strings: - $not_jar = "META-INF/" - $not_dwarf = "_DWARF" - $not_kext = "_.SYMDEF SORTED" - - condition: - (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) and none of ($not*) -} +include "rules/global/global.yara" rule macos_chflags_hidden: critical { meta: @@ -38,5 +30,5 @@ rule cocoa_bundle_dropper: critical { $platform = "isPlatformOrVariantPlatformVersionAtLeast" fullword condition: - tool_transfer_macho and $shared and 5 of them + global_specific_macho and $shared and 5 of them } diff --git a/rules/c2/tool_transfer/python.yara b/rules/c2/tool_transfer/python.yara index 4f30f0ec3..d5a59b4c6 100644 --- a/rules/c2/tool_transfer/python.yara +++ b/rules/c2/tool_transfer/python.yara @@ -1,46 +1,4 @@ -private rule probably_python_tt { - strings: - $import = "import " - $f_common = /\s(def|if|with|else:) / - $f_exotic = /exec\(|b64decode|bytes\(/ - - condition: - filesize < 10MB and $import in (1..1024) and any of ($f*) -} - -private rule py_fetcher: medium { - meta: - description = "fetches content" - filetypes = "py" - - strings: - $http_requests = "requests.get" fullword - $http_requests_post = "requests.post" fullword - $http_urllib = "urllib.request" fullword - $http_urlopen = "urlopen" fullword - $git_git = /git.Git\(.{0,64}/ - $http_curl = "curl" fullword - $http_wget = "wget" fullword - - condition: - probably_python_tt and any of them -} - -private rule py_runner { - meta: - description = "runs programs" - filetypes = "py" - - strings: - $os_system = /os.system\([\"\'\w\ \-\)\/]{0,64}/ - $os_startfile = /os.startfile\([\"\'\w\ \-\)\/]{0,64}/ - $os_popen = /os.spopen\([\"\'\w\ \-\)\/]{0,64}/ - $subprocess = /subprocess.\w{1,32}\([\"\'\/\w\ \-\)]{0,64}/ - $system = /system\([\"\'\w\ \-\)\/]{0,64}/ - - condition: - probably_python_tt and any of them -} +include "rules/global/global.yara" rule py_dropper: medium { meta: @@ -52,7 +10,7 @@ rule py_dropper: medium { $write = "write(" condition: - filesize < 16384 and $open and $write and py_fetcher and py_runner + filesize < 16384 and $open and $write and global_py_fetcher and global_py_runner } rule py_arch_dropper: medium { @@ -75,7 +33,7 @@ rule py_arch_dropper: medium { $exec_run = "run" fullword condition: - filesize < 1MB and any of ($os*) and any of ($arch*) and any of ($download*) and (any of ($exec*) or py_runner) + filesize < 1MB and any of ($os*) and any of ($arch*) and any of ($download*) and (any of ($exec*) or global_py_runner) } rule py_dropper_obfuscated: high { @@ -90,7 +48,7 @@ rule py_dropper_obfuscated: high { $ob_codecs = "codecs.decode" condition: - filesize < 16000 and $open and $write and any of ($ob_*) and py_fetcher and py_runner + filesize < 16000 and $open and $write and any of ($ob_*) and global_py_fetcher and global_py_runner } rule py_dropper_tiny: high { @@ -103,7 +61,7 @@ rule py_dropper_tiny: high { $write = "write(" condition: - filesize < 900 and $open and $write and py_fetcher and py_runner + filesize < 900 and $open and $write and global_py_fetcher and global_py_runner } rule py_dropper_chmod: high { @@ -119,29 +77,7 @@ rule py_dropper_chmod: high { $val_770 = "770" condition: - filesize < 1MB and py_fetcher and py_runner and $chmod and any of ($val*) -} - -private rule tool_transfer_pythonSetup { - strings: - $if_distutils = /from distutils.core import .{0,32}setup/ - $if_setuptools = /from setuptools import .{0,32}setup/ - $i_setuptools = "import setuptools" - $setup = "setup(" - - $not_setup_example = ">>> setup(" - $not_setup_todict = "setup(**config.todict()" - $not_import_quoted = "\"from setuptools import setup" - $not_setup_quoted = "\"setup(name=" - $not_distutils = "from distutils.errors import" - $not_dir = "dist-packages/setuptools" - $not_fetch = "fetch_distribution" - $not_hopper1 = "PACKAGE_NAME = \"flashattn-hopper\"" - $not_hopper2 = "check_if_cuda_home_none(\"--fahopper\")" - $not_hopper3 = "name=\"flashattn_hopper_cuda\"," - - condition: - filesize < 128KB and $setup and any of ($i*) and none of ($not*) + filesize < 1MB and global_py_fetcher and global_py_runner and $chmod and any of ($val*) } rule setuptools_fetcher: suspicious { @@ -150,7 +86,7 @@ rule setuptools_fetcher: suspicious { filetypes = "py" condition: - tool_transfer_pythonSetup and py_fetcher + global_python_setup and global_py_fetcher } rule setuptools_fetch_run: critical { @@ -164,7 +100,7 @@ rule setuptools_fetch_run: critical { $not_hopper3 = "name=\"flashattn_hopper_cuda\"," condition: - setuptools_fetcher and py_runner and none of ($not*) + setuptools_fetcher and global_py_runner and none of ($not*) } rule setuptools_dropper: critical { @@ -173,7 +109,7 @@ rule setuptools_dropper: critical { filetypes = "py" condition: - tool_transfer_pythonSetup and py_dropper + global_python_setup and py_dropper } rule dropper_imports: high { @@ -204,6 +140,6 @@ rule oneline: high { $urlopen = /\.write\(.{0,8}urlopen\("http.{0,128}\"\).read\(\)/ condition: - filesize < 512KB and any of them and py_fetcher and py_runner + filesize < 512KB and any of them and global_py_fetcher and global_py_runner } diff --git a/rules/data/builtin/multiple.yara b/rules/data/builtin/multiple.yara index e4567dad1..ebe682b13 100644 --- a/rules/data/builtin/multiple.yara +++ b/rules/data/builtin/multiple.yara @@ -1,31 +1,6 @@ import "elf" -private rule _bundled_openssl: medium { - meta: - description = "includes bundled copy of OpenSSL" - - strings: - $ref = "OpenSSL/" - $aes_part = "AES part of OpenSSL" - $montgomery = "Montgomery Multiplication for x86_64, CRYPTOGAMS" - $rc4 = "RC4 for x86_64, CRYPTOGAMS" - - condition: - filesize > 1024 and filesize < 150MB and elf.type == elf.ET_EXEC and uint32(0) == 1179403647 and any of them -} - -private rule _bundled_glibc: medium { - meta: - description = "includes bundled copy of glibc" - - strings: - $glibc_private = "GLIBC_PRIVATE" - $glibc_tunables = "GLIBC_TUNABLES" - $setup_vdso = "setup_vdso" - - condition: - filesize > 1024 and filesize < 25MB and elf.type == elf.ET_EXEC and uint32(0) == 1179403647 and all of them -} +include "rules/global/global.yara" rule elf_with_bundled_glibc_and_openssl: high { meta: @@ -33,5 +8,5 @@ rule elf_with_bundled_glibc_and_openssl: high { filetypes = "elf" condition: - _bundled_openssl and _bundled_glibc + global_bundled_openssl and global_bundled_glibc } diff --git a/rules/discover/multiple.yara b/rules/discover/multiple.yara index 6862fddac..3389b4ebd 100644 --- a/rules/discover/multiple.yara +++ b/rules/discover/multiple.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule sys_net_recon: medium { meta: description = "collects system and network information" @@ -62,35 +64,6 @@ rule user_sys_net_disk_recon: high { filesize < 512KB and any of ($sys*) and any of ($net*) and any of ($user*) and any of ($disk*) } -private rule discover_obfuscate { - strings: - $b64decode = "b64decode" - $base64 = "base64" - $codecs = "codecs.decode" - $x_decode = /\w{0,16}XorDecode[\w]{0,32}/ - $x_encode = /\w{0,16}XorEncode[\w]{0,32}/ - $x_file = /\w{0,16}XorFile[\w]{0,32}/ - $x_decode_ = /\w{0,16}xor_decode[\w]{0,32}/ - $x_encode_ = /\w{0,16}xor_encode[\w]{0,32}/ - $x_file_ = /\w{0,16}xor_file[\w]{0,32}/ - - condition: - filesize < 512KB and any of them -} - -private rule discover_exfil { - strings: - $f_app_json = "application/json" - $f_post = "requests.post" - $f_nsurl = "NSURLRequest" - $f_curl = /curl.{0,32}-X POST/ - - $not_requests_utils = "requests.utils" - - condition: - filesize < 512KB and any of ($f*) and none of ($not*) -} - rule sys_net_recon_exfil: high { meta: description = "may exfiltrate collected system and network information" @@ -100,5 +73,5 @@ rule sys_net_recon_exfil: high { $not_cloudinit = "cloudinit" fullword condition: - sys_net_recon and discover_obfuscate and discover_exfil and none of ($not*) + sys_net_recon and global_obfuscate and global_exfil and none of ($not*) } diff --git a/rules/discover/user/username-get.yara b/rules/discover/user/username-get.yara index 8e0dfacc9..cc0ed8f3d 100644 --- a/rules/discover/user/username-get.yara +++ b/rules/discover/user/username-get.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule getlogin { meta: syscall = "getlogin" @@ -27,23 +29,6 @@ rule whoami: medium { any of them } -private rule user_pythonSetup { - strings: - $if_distutils = /from distutils.core import .{0,32}setup/ - $if_setuptools = /from setuptools import .{0,32}setup/ - $i_setuptools = "import setuptools" - $setup = "setup(" - - $not_setup_example = ">>> setup(" - $not_setup_todict = "setup(**config.todict()" - $not_import_quoted = "\"from setuptools import setup" - $not_setup_quoted = "\"setup(name=" - $not_distutils = "from distutils.errors import" - - condition: - filesize < 128KB and $setup and any of ($i*) and none of ($not*) -} - rule pysetup_gets_login: high { meta: description = "Python library installer gets login information" @@ -55,5 +40,5 @@ rule pysetup_gets_login: high { $ref3 = "whoami" fullword condition: - user_pythonSetup and any of them + global_python_setup and any of them } diff --git a/rules/evasion/indicator_blocking/hidden_window.yara b/rules/evasion/indicator_blocking/hidden_window.yara index 3ed227b4d..4114e2cb8 100644 --- a/rules/evasion/indicator_blocking/hidden_window.yara +++ b/rules/evasion/indicator_blocking/hidden_window.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule subprocess_CREATE_NO_WINDOW: medium { meta: description = "runs commands, hides windows" @@ -11,23 +13,6 @@ rule subprocess_CREATE_NO_WINDOW: medium { filesize < 32KB and all of them } -private rule hidden_window_pythonSetup { - strings: - $if_distutils = /from distutils.core import .{0,32}setup/ - $if_setuptools = /from setuptools import .{0,32}setup/ - $i_setuptools = "import setuptools" - $setup = "setup(" - - $not_setup_example = ">>> setup(" - $not_setup_todict = "setup(**config.todict()" - $not_import_quoted = "\"from setuptools import setup" - $not_setup_quoted = "\"setup(name=" - $not_distutils = "from distutils.errors import" - - condition: - filesize < 128KB and $setup and any of ($i*) in (0..1024) and none of ($not*) -} - rule subprocess_CREATE_NO_WINDOW_setuptools: high { meta: description = "runs commands, hides windows" @@ -38,7 +23,7 @@ rule subprocess_CREATE_NO_WINDOW_setuptools: high { $no_window = "CREATE_NO_WINDOW" condition: - filesize < 32KB and hidden_window_pythonSetup and all of them + filesize < 32KB and global_python_setup and all of them } rule subprocess_CREATE_NO_WINDOW_high: high { diff --git a/rules/evasion/indicator_blocking/mask_exceptions.yara b/rules/evasion/indicator_blocking/mask_exceptions.yara index 6f447a1fe..d9ad8f2c8 100644 --- a/rules/evasion/indicator_blocking/mask_exceptions.yara +++ b/rules/evasion/indicator_blocking/mask_exceptions.yara @@ -1,20 +1,6 @@ import "math" -private rule indicator_blocking_pythonSetup { - strings: - $if_distutils = /from distutils.core import .{0,32}setup/ - $if_setuptools = /from setuptools import .{0,32}setup/ - $i_setuptools = "import setuptools" - $setup = "setup(" - $not_setup_example = ">>> setup(" - $not_setup_todict = "setup(**config.todict()" - $not_import_quoted = "\"from setuptools import setup" - $not_setup_quoted = "\"setup(name=" - $not_distutils = "from distutils.errors import" - - condition: - filesize < 131072 and $setup and any of ($i*) and none of ($not*) -} +include "rules/global/global.yara" rule py_no_fail: medium { meta: @@ -35,7 +21,7 @@ rule setuptools_no_fail: suspicious { filetypes = "py" condition: - indicator_blocking_pythonSetup and py_no_fail + global_python_setup and py_no_fail } rule php_disable_errors: medium { diff --git a/rules/evasion/logging/wipe.yara b/rules/evasion/logging/wipe.yara index cd2afb756..0ca99de82 100644 --- a/rules/evasion/logging/wipe.yara +++ b/rules/evasion/logging/wipe.yara @@ -1,21 +1,4 @@ -private rule sensitive_log_files { - strings: - $wtmp = "/var/log/wtmp" - $secure = "/var/log/secure" - $cron = "/var/log/cron" - $iptables = "/var/log/iptables.log" - $auth = "/var/log/auth.log" - $cron_log = "/var/log/cron.log" - $httpd = "/var/log/httpd" - $syslog = "/var/log/syslog" - $btmp = "/var/log/btmp" - $lastlog = "/var/log/lastlog" - $run_log = "/run/log/" - $mail_log = "/var/spool/mail/root" - - condition: - filesize < 16KB and 2 of them -} +include "rules/global/global.yara" rule echo_log_wiper: critical { meta: @@ -26,7 +9,7 @@ rule echo_log_wiper: critical { $var_log = /echo.{0,4}\> {0,2}\/var\/log\/\w{0,8}/ condition: - filesize < 16KB and sensitive_log_files and any of them + filesize < 16KB and global_sensitive_log_files and any of them } rule log_remover: critical { @@ -38,5 +21,5 @@ rule log_remover: critical { $var_log = /rm {1,2}-{0,4}\/var\/log\/\w{0,8}/ condition: - filesize < 16KB and sensitive_log_files and any of them + filesize < 16KB and global_sensitive_log_files and any of them } diff --git a/rules/evasion/net/hide_ports.yara b/rules/evasion/net/hide_ports.yara index 5dc0c9a22..8e74e2101 100644 --- a/rules/evasion/net/hide_ports.yara +++ b/rules/evasion/net/hide_ports.yara @@ -1,12 +1,4 @@ -private rule net_macho { - condition: - uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178 -} - -private rule net_elf { - condition: - uint32(0) == 1179403647 -} +include "rules/global/global.yara" rule hides_ports: high { meta: @@ -22,5 +14,5 @@ rule hides_ports: high { $hidden_port = "hidden_port" condition: - filesize < 2MB and (net_elf or net_macho) and any of ($bin*) and any of ($hid*) + filesize < 2MB and (global_elf_or_macho) and any of ($bin*) and any of ($hid*) } diff --git a/rules/evasion/self_deletion/run_and_delete.yara b/rules/evasion/self_deletion/run_and_delete.yara index 6557dd681..904ff6be5 100644 --- a/rules/evasion/self_deletion/run_and_delete.yara +++ b/rules/evasion/self_deletion/run_and_delete.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule tiny_copy_run_delete: critical { meta: description = "copy executable, run, and delete" @@ -36,24 +38,6 @@ rule fetch_run_sleep_delete: critical { filesize < 1KB and $url and $sleep and $rm and any of ($path*) and any of ($run*) } -private rule run_delete_py_fetcher: medium { - meta: - description = "fetches content" - filetypes = "py" - - strings: - $http_requests = "requests.get" fullword - $http_requests_post = "requests.post" fullword - $http_urllib = "urllib.request" fullword - $http_urlopen = "urlopen" fullword - $git_git = /git.Git\(.{0,64}/ - $http_curl = "curl" fullword - $http_wget = "wget" fullword - - condition: - any of them -} - rule python_setsid_remove: high { meta: description = "fetch, run in background, delete" @@ -65,7 +49,7 @@ rule python_setsid_remove: high { $remove = "os.remove(" condition: - filesize < 1MB and all of them and run_delete_py_fetcher and @remove > @subprocess and @remove - @subprocess < 256 + filesize < 1MB and all of them and global_py_fetcher and @remove > @subprocess and @remove - @subprocess < 256 } rule run_sleep_delete: critical { diff --git a/rules/exec/program/opaque.yara b/rules/exec/program/opaque.yara index f9dfd28ef..2cef35225 100644 --- a/rules/exec/program/opaque.yara +++ b/rules/exec/program/opaque.yara @@ -1,13 +1,7 @@ -private rule program_small_macho { - strings: - $stub_helper = "__stub_helper" - - condition: - filesize < 1MB and (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962) and $stub_helper -} - import "math" +include "rules/global/global.yara" + rule macho_opaque_binary: high { meta: description = "opaque binary executes mystery command-lines" @@ -24,7 +18,7 @@ rule macho_opaque_binary: high { $not_java = "java/lang" condition: - program_small_macho and #word_with_spaces < 8 and #libc_call < 6 and all of ($f*) and none of ($not*) + global_small_macho and #word_with_spaces < 8 and #libc_call < 6 and all of ($f*) and none of ($not*) } rule macho_opaque_binary_long_str: high { @@ -45,7 +39,7 @@ rule macho_opaque_binary_long_str: high { $long_low_str = /\x00[a-z0-9]{3000}/ condition: - program_small_macho and #word_with_spaces < 10 and #libc_call < 15 and all of ($f*) and any of ($long*) and none of ($not*) + global_stub_macho and #word_with_spaces < 10 and #libc_call < 15 and all of ($f*) and any of ($long*) and none of ($not*) } rule decoded_or_encoded_cmd: medium { diff --git a/rules/exec/shell/relative-semicolon.yara b/rules/exec/shell/relative-semicolon.yara index e6682ccb6..3698afc75 100644 --- a/rules/exec/shell/relative-semicolon.yara +++ b/rules/exec/shell/relative-semicolon.yara @@ -1,10 +1,4 @@ -private rule local_cd { - strings: - $cd = /cd [a-z]{4,12}; \.\// - - condition: - any of them -} +include "rules/global/global.yara" rule semicolon_relative_path_cd: medium { meta: @@ -25,5 +19,5 @@ rule semicolon_relative_path_high: high { $semi_relative = /[\/\w]{3,};[ +]{0,8}\.\/\.{0,8}\w{3,}/ condition: - any of them and not local_cd + any of them and not global_local_cd } diff --git a/rules/exfil/discord.yara b/rules/exfil/discord.yara index 6c15d1f9d..0a64b7554 100644 --- a/rules/exfil/discord.yara +++ b/rules/exfil/discord.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule discord_bot: high { meta: description = "Uses the Discord webhooks API" @@ -26,41 +28,10 @@ rule discord_bot: high { any of them and none of ($not*) } -private rule iplookup_website_value_copy: high { - meta: - description = "public service to discover external IP address" - - strings: - $ipify = "ipify.org" - $wtfismyip = "wtfismyip" - $iplogger = "iplogger.org" - $getjsonip = "getjsonip" - $ipconfig_me = "ifconfig.me" - $icanhazip = "icanhazip" - $ident_me = "ident.me" fullword - $showip_net = "showip.net" fullword - $ifconfig_io = "ifconfig.io" fullword - $ifconfig_co = "ifconfig.co" fullword - $ipinfo = "ipinfo.io" - $ipify_b = "ipify.org" base64 - $wtfismyip_b = "wtfismyip" base64 - $iplogger_b = "iplogger.org" base64 - $getjsonip_b = "getjsonip" base64 - $ipinfo_b = "ipinfo.io" base64 - $ipify_x = "ipify.org" xor(1-255) - $wtfismyip_x = "wtfismyip" xor(1-255) - $iplogger_x = "iplogger.org" xor(1-255) - $getjsonip_x = "getjsonip" xor(1-255) - $ipinfo_x = "ipinfo.io" xor(1-255) - - condition: - any of them -} - rule discord_exfil: critical { meta: description = "exfiltrates data via discord webhook" condition: - filesize < 100MB and discord_bot and iplookup_website_value_copy + filesize < 100MB and discord_bot and global_iplookup_website } diff --git a/rules/exfil/nodejs.yara b/rules/exfil/nodejs.yara index 7c3d23044..8bed2717a 100644 --- a/rules/exfil/nodejs.yara +++ b/rules/exfil/nodejs.yara @@ -1,5 +1,7 @@ import "math" +include "rules/global/global.yara" + rule nodejs_sysinfoexfil: high { meta: description = "may gather and exfiltrate system information" @@ -130,31 +132,6 @@ rule post_hardcoded_hardcoded_host_os: high { filesize < 256KB and any of ($ref*) and $post and ((math.abs(@ref - @post) <= 128) or ((math.abs(@ref2 - @post) <= 128))) and $os } -private rule nodejs_iplookup_website: high { - meta: - description = "public service to discover external IP address" - - strings: - $ipify = /ipify\.org{0,1}/ - $wtfismyip = "wtfismyip" - $iplogger = "iplogger.org" - $getjsonip = "getjsonip" - $ipconfig_me = "ifconfig.me" - $icanhazip = "icanhazip" - $grabify = "grabify.link" - $ident_me = "ident.me" fullword - $showip_net = "showip.net" fullword - $ifconfig_io = "ifconfig.io" fullword - $ifconfig_co = "ifconfig.co" fullword - $ipinfo = "ipinfo.io" - $check_ip = "checkip.amazonaws.com" - - $not_pypi_index = "testpack-id-lb001" - - condition: - filesize < 250MB and any of them and none of ($not*) -} - rule get_hardcoded_hardcoded_host_os: critical { meta: description = "leaks host information to a hardcoded host" @@ -168,5 +145,5 @@ rule get_hardcoded_hardcoded_host_os: critical { $i_os_userinfo = "os.userInfo" condition: - filesize < 256KB and $ref and (any of ($i*) or nodejs_iplookup_website) + filesize < 256KB and $ref and (any of ($i*) or global_iplookup_website) } diff --git a/rules/exfil/npm.yara b/rules/exfil/npm.yara index 504ddf422..5e6eb468e 100644 --- a/rules/exfil/npm.yara +++ b/rules/exfil/npm.yara @@ -1,17 +1,4 @@ -private rule package_scripts { - strings: - $npm_name = /"name":/ - $npm_version = /"version":/ - $npm_description = /"description":/ - $npm_lint = /"lint":/ - $npm_test = /"test":/ - $npm_postversion = /"postversion":/ - $npm_postinstall = /"postinstall":/ - $scripts = /"scripts":/ - - condition: - filesize < 32KB and 3 of ($npm*) and $scripts -} +include "rules/global/global.yara" rule npm_fetcher: high { meta: @@ -22,7 +9,7 @@ rule npm_fetcher: high { $url = /https{0,1}:\/\/[\w][\w\.\/\-_\?=\@]{8,64}/ condition: - package_scripts and $fetch and $url + global_package_scripts and $fetch and $url } rule npm_dev_tcp: critical { @@ -33,7 +20,7 @@ rule npm_dev_tcp: critical { $dev_tcp = /\/dev\/tcp\/[\w\.\/]{0,32}/ condition: - package_scripts and $dev_tcp + global_package_scripts and $dev_tcp } rule npm_ping: critical { @@ -44,7 +31,7 @@ rule npm_ping: critical { $ping = /ping -\w [\w\-\. \$]{0,63}/ condition: - package_scripts and $ping + global_package_scripts and $ping } rule npm_sensitive_files: high { @@ -60,7 +47,7 @@ rule npm_sensitive_files: high { $ = "/etc/passwd" condition: - package_scripts and any of them + global_package_scripts and any of them } rule npm_recon_commands: high { @@ -72,5 +59,5 @@ rule npm_recon_commands: high { $ = "cat /etc/shadow" condition: - package_scripts and any of them + global_package_scripts and any of them } diff --git a/rules/exfil/oauth.yara b/rules/exfil/oauth.yara index ac5c1f723..c4320c588 100644 --- a/rules/exfil/oauth.yara +++ b/rules/exfil/oauth.yara @@ -1,12 +1,4 @@ -private rule post_json { - strings: - $json = "application/json" - $POST = "POST" - $encode_stringify = "JSON.stringify" - - condition: - $json and $POST and any of ($encode*) -} +include "rules/global/global.yara" rule possible_oauth_stealer: high { meta: @@ -29,7 +21,7 @@ rule possible_oauth_stealer: high { $o_microsoft5 = "code_challenge_method" condition: - filesize < 10MB and post_json and 5 of ($o*) + filesize < 10MB and global_post_json and 5 of ($o*) } rule oauth_stealer: critical { diff --git a/rules/false_positives/py_hatch.yara b/rules/false_positives/py_hatch.yara index 3c0f1f9e4..6f54ea0f6 100644 --- a/rules/false_positives/py_hatch.yara +++ b/rules/false_positives/py_hatch.yara @@ -2,6 +2,7 @@ rule migrate_py: override { meta: description = "migrate.py" setuptools_eval_high = "medium" + setuptools_cmd_exec = "medium" strings: $env = "'_HATCHLING_PORT_ADD_'" diff --git a/rules/false_positives/setuptools.yara b/rules/false_positives/setuptools.yara index 510c127ae..252000c5b 100644 --- a/rules/false_positives/setuptools.yara +++ b/rules/false_positives/setuptools.yara @@ -2,6 +2,7 @@ rule setuptools_namespaces: override { meta: description = "namespaces.py" setuptools_exec_high = "low" + setuptools_eval_high = "low" strings: $func1 = "def iter_namespace_pkgs(" diff --git a/rules/fs/path/applications.yara b/rules/fs/path/applications.yara index e9ef9ebb4..89a769c40 100644 --- a/rules/fs/path/applications.yara +++ b/rules/fs/path/applications.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule app_path: medium { meta: description = "references hardcoded application path" @@ -9,16 +11,6 @@ rule app_path: medium { any of them } -private rule applicatons_macho { - strings: - $not_jar = "META-INF/" - $not_dwarf = "_DWARF" - $not_kext = "_.SYMDEF SORTED" - - condition: - (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) and none of ($not*) -} - rule macho_app_path: high { meta: description = "references hardcoded application path" @@ -28,7 +20,7 @@ rule macho_app_path: high { $ref = /\/Applications\/.{0,32}\.app\/Contents\/MacOS\/[\w \.\-]{0,32}/ condition: - applicatons_macho and any of them + global_specific_macho and any of them } rule mac_applications: medium { @@ -40,5 +32,5 @@ rule mac_applications: medium { $ref = "/Applications" fullword condition: - applicatons_macho and any of them + global_specific_macho and any of them } diff --git a/rules/global/global.yara b/rules/global/global.yara new file mode 100644 index 000000000..ba4f26c3d --- /dev/null +++ b/rules/global/global.yara @@ -0,0 +1,320 @@ +import "elf" + +private rule global_binary { + condition: + filesize < 40MB and (uint32(0) == 1179403647 or uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962) +} + +private rule global_bundled_glibc { + meta: + description = "includes bundled copy of glibc" + filetypes = "elf,so" + + strings: + $glibc_private = "GLIBC_PRIVATE" + $glibc_tunables = "GLIBC_TUNABLES" + $setup_vdso = "setup_vdso" + + condition: + filesize > 1024 and filesize < 25MB and elf.type == elf.ET_EXEC and uint32(0) == 1179403647 and all of them +} + +private rule global_bundled_openssl { + meta: + description = "includes bundled copy of OpenSSL" + filetypes = "elf,so" + + strings: + $ref = "OpenSSL/" + $aes_part = "AES part of OpenSSL" + $montgomery = "Montgomery Multiplication for x86_64, CRYPTOGAMS" + $rc4 = "RC4 for x86_64, CRYPTOGAMS" + + condition: + filesize > 1024 and filesize < 150MB and elf.type == elf.ET_EXEC and uint32(0) == 1179403647 and any of them +} + +private rule global_container_managers { + strings: + $containerd = "github.com/containerd/containerd" + $systemd = "SYSTEMD_PROC_CMDLINE" + $snapd = "snapcore/snapd" + + condition: + any of them +} + +private rule global_elf_or_macho { + condition: + uint32(0) == 1179403647 or (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) +} + +private rule global_exfil { + strings: + $f_app_json = "application/json" + $f_post = "requests.post" + $f_nsurl = "NSURLRequest" + $f_curl = /curl.{0,32}-X POST/ + + $not_requests_utils = "requests.utils" + + condition: + filesize < 512KB and any of ($f*) and none of ($not*) +} + +private rule global_iplookup_website { + meta: + description = "public service to discover external IP address" + + strings: + $ipify = "ipify.org" + $wtfismyip = "wtfismyip" + $iplogger = "iplogger.org" + $getjsonip = "getjsonip" + $ipconfig_me = "ifconfig.me" + $icanhazip = "icanhazip" + $ident_me = "ident.me" fullword + $showip_net = "showip.net" fullword + $ifconfig_io = "ifconfig.io" fullword + $ifconfig_co = "ifconfig.co" fullword + $ipinfo = "ipinfo.io" + $ipify_b = "ipify.org" base64 + $wtfismyip_b = "wtfismyip" base64 + $iplogger_b = "iplogger.org" base64 + $getjsonip_b = "getjsonip" base64 + $ipinfo_b = "ipinfo.io" base64 + $ipify_x = "ipify.org" xor(1-255) + $wtfismyip_x = "wtfismyip" xor(1-255) + $iplogger_x = "iplogger.org" xor(1-255) + $getjsonip_x = "getjsonip" xor(1-255) + $ipinfo_x = "ipinfo.io" xor(1-255) + + $not_pypi_index = "testpack-id-lb001" + + condition: + filesize < 250MB and any of them and none of ($not*) +} + +private rule global_legal_license { + strings: + $ = "using, exploiting or modifying the Software" + $ = "exploit the Information commercially" + $ = "otherwise exploited by anyone for any purpose" + + condition: + any of them +} + +private rule global_local_cd { + strings: + $cd = /cd [a-z]{4,12}; \.\// + + condition: + any of them +} + +private rule global_macho { + condition: + (uint32(0) == 4277009102 + or uint32(0) == 3472551422 + or uint32(0) == 4277009103 + or uint32(0) == 3489328638 + or uint32(0) == 3405691582 + or uint32(0) == 3199925962 + or uint32(0) == 3405691583 + or uint32(0) == 3216703178) +} + +private rule global_normal_elf { + condition: + filesize < 64MB and uint32(0) == 1179403647 +} + +private rule global_obfuscate { + strings: + $b64decode = "b64decode" + $base64 = "base64" + $codecs = "codecs.decode" + $x_decode = /\w{0,16}XorDecode[\w]{0,32}/ + $x_encode = /\w{0,16}XorEncode[\w]{0,32}/ + $x_file = /\w{0,16}XorFile[\w]{0,32}/ + $x_decode_ = /\w{0,16}xor_decode[\w]{0,32}/ + $x_encode_ = /\w{0,16}xor_encode[\w]{0,32}/ + $x_file_ = /\w{0,16}xor_file[\w]{0,32}/ + + condition: + filesize < 512KB and any of them +} + +private rule global_package_scripts { + strings: + $npm_name = /"name":/ + $npm_version = /"version":/ + $npm_description = /"description":/ + $npm_lint = /"lint":/ + $npm_test = /"test":/ + $npm_postversion = /"postversion":/ + $npm_postinstall = /"postinstall":/ + $scripts = /"scripts":/ + + condition: + filesize < 32KB and 3 of ($npm*) and $scripts +} + +private rule global_post_json { + strings: + $json = "application/json" + $POST = "POST" + $encode_stringify = "JSON.stringify" + + condition: + $json and $POST and any of ($encode*) +} + +private rule global_py_fetcher { + meta: + description = "fetches content" + filetypes = "py" + + strings: + $http_requests = "requests.get" fullword + $http_requests_post = "requests.post" fullword + $http_urllib = "urllib.request" fullword + $http_urlopen = "urlopen" fullword + $git_git = /git.Git\(.{0,64}/ + $http_curl = "curl" fullword + $http_wget = "wget" fullword + + condition: + any of them +} + +private rule global_py_runner { + meta: + description = "runs programs" + filetypes = "py" + + strings: + $os_system = /os.system\([\"\'\w\ \-\)\/]{0,64}/ + $os_startfile = /os.startfile\([\"\'\w\ \-\)\/]{0,64}/ + $os_popen = /os.spopen\([\"\'\w\ \-\)\/]{0,64}/ + $subprocess = /subprocess.\w{1,32}\([\"\'\/\w\ \-\)]{0,64}/ + $system = /system\([\"\'\w\ \-\)\/]{0,64}/ + + condition: + any of them +} + +private rule global_python_setup { + meta: + filetypes = "py" + + strings: + $if_distutils = /from distutils.core import .{0,32}setup/ + $if_setuptools = /from setuptools import .{0,32}setup/ + $i_setuptools = "import setuptools" + $setup = "setup(" + + $not_setup_example = ">>> setup(" + $not_setup_todict = "setup(**config.todict()" + $not_import_quoted = "\"from setuptools import setup" + $not_setup_quoted = "\"setup(name=" + $not_distutils = "from distutils.errors import" + $not_numba = "https://github.com/numba/numba" + + $not_hopper1 = "PACKAGE_NAME = \"flashattn-hopper\"" + $not_hopper2 = "check_if_cuda_home_none(\"--fahopper\")" + $not_hopper3 = "name=\"flashattn_hopper_cuda\"," + + condition: + filesize < 131072 and $setup and any of ($i*) and none of ($not*) +} + +private rule global_sensitive_log_files { + strings: + $wtmp = "/var/log/wtmp" + $secure = "/var/log/secure" + $cron = "/var/log/cron" + $iptables = "/var/log/iptables.log" + $auth = "/var/log/auth.log" + $cron_log = "/var/log/cron.log" + $httpd = "/var/log/httpd" + $syslog = "/var/log/syslog" + $btmp = "/var/log/btmp" + $lastlog = "/var/log/lastlog" + $run_log = "/run/log/" + $mail_log = "/var/spool/mail/root" + + condition: + filesize < 16KB and 2 of them +} + +private rule global_small_binary { + condition: + filesize < 10MB and (uint32(0) == 1179403647 or uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962) +} + +private rule global_small_elf { + condition: + filesize < 400KB and uint32(0) == 1179403647 +} + +private rule global_small_elf_or_macho { + condition: + filesize > 1MB and filesize < 8MB and (uint32(0) == 1179403647 or uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962) +} + +private rule global_small_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) +} + +private rule global_specific_macho { + strings: + $not_jar = "META-INF/" + $not_dwarf = "_DWARF" + $not_kext = "_.SYMDEF SORTED" + + condition: + (uint32(0) == 4277009102 + or uint32(0) == 3472551422 + or uint32(0) == 4277009103 + or uint32(0) == 3489328638 + or uint32(0) == 3405691582 + or uint32(0) == 3199925962 + or uint32(0) == 3405691583 + or uint32(0) == 3216703178) + and none of ($not*) +} + +private rule global_stub_macho { + strings: + $stub_helper = "__stub_helper" + + condition: + filesize < 1MB and (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962) and $stub_helper +} + +private rule global_ufw_tool { + strings: + $not_route = "route-insert" + $not_statusverbose = "statusverbose" + $not_enables_the = "enables the" + $not_enable_the = "enable the" + $not_enable = "ufw enable" + + condition: + filesize < 256KB and any of them +} + +private rule global_word_list { + strings: + $scorpion = "scorpion" + $superman = "superman" + $porsche = "porsche" + $cardinal = "cardinal" + $wombat = "wombat" + + condition: + filesize < 100MB and 3 of them +} diff --git a/rules/impact/degrade/firewall.yara b/rules/impact/degrade/firewall.yara index f4c589a03..efd10283d 100644 --- a/rules/impact/degrade/firewall.yara +++ b/rules/impact/degrade/firewall.yara @@ -1,5 +1,7 @@ import "math" +include "rules/global/global.yara" + rule selinux_firewall: high linux { meta: filetypes = "elf,so" @@ -21,18 +23,6 @@ rule selinux_firewall: high linux { filesize < 1MB and $selinux and any of ($f*) and none of ($not*) } -private rule ufw_tool { - strings: - $not_route = "route-insert" - $not_statusverbose = "statusverbose" - $not_enables_the = "enables the" - $not_enable_the = "enable the" - $not_enable = "ufw enable" - - condition: - filesize < 256KB and any of them -} - rule ufw_disable_word: high { meta: description = "disables ufw firewall" @@ -41,7 +31,7 @@ rule ufw_disable_word: high { $ref = /ufw['", ]{1,4}disable/ fullword condition: - filesize < 256KB and $ref and not ufw_tool + filesize < 256KB and $ref and not global_ufw_tool } rule firewall_iptables_disable: high { diff --git a/rules/impact/exploit/breakout.yara b/rules/impact/exploit/breakout.yara index 8566fd40c..201f58595 100644 --- a/rules/impact/exploit/breakout.yara +++ b/rules/impact/exploit/breakout.yara @@ -1,12 +1,4 @@ -private rule container_managers { - strings: - $containerd = "github.com/containerd/containerd" - $systemd = "SYSTEMD_PROC_CMDLINE" - $snapd = "snapcore/snapd" - - condition: - any of them -} +include "rules/global/global.yara" rule probable_container_breakout: high linux { meta: @@ -30,7 +22,7 @@ rule probable_container_breakout: high linux { $not_systemd = "SYSTEMD_PROC_CMDLINE" condition: - filesize < 1MB and 4 of ($x*) and none of ($not*) and not container_managers + filesize < 1MB and 4 of ($x*) and none of ($not*) and not global_container_managers } rule possible_container_breakout: medium linux { @@ -53,5 +45,5 @@ rule possible_container_breakout: medium linux { $cgroup_procs = "cgroup.procs" condition: - filesize < 1MB and 3 of them and not container_managers + filesize < 1MB and 3 of them and not global_container_managers } diff --git a/rules/impact/exploit/exploit.yara b/rules/impact/exploit/exploit.yara index 7d86335e6..12fc5d98c 100644 --- a/rules/impact/exploit/exploit.yara +++ b/rules/impact/exploit/exploit.yara @@ -1,12 +1,4 @@ -private rule legal_license { - strings: - $ = "using, exploiting or modifying the Software" - $ = "exploit the Information commercially" - $ = "otherwise exploited by anyone for any purpose" - - condition: - any of them -} +include "rules/global/global.yara" rule exploitation: medium { meta: @@ -20,7 +12,7 @@ rule exploitation: medium { $not_ms_example = "Drive-by Compromise" condition: - any of ($ref*) and none of ($not*) and not legal_license + any of ($ref*) and none of ($not*) and not global_legal_license } rule install_exploit: high { @@ -34,7 +26,7 @@ rule install_exploit: high { $not_ms_example = "Drive-by Compromise" condition: - any of ($ref*) and none of ($not*) and not legal_license + any of ($ref*) and none of ($not*) and not global_legal_license } rule explot: high { @@ -57,7 +49,7 @@ rule Exploit: medium { $not_reduction = "Exploit reduction" condition: - any of ($ref*) and none of ($not*) and not legal_license + any of ($ref*) and none of ($not*) and not global_legal_license } rule exploiter: high { @@ -73,7 +65,7 @@ rule exploiter: high { $not_pypi_index = "testpack-id-lb001" condition: - any of ($ref*) and none of ($not*) and not legal_license + any of ($ref*) and none of ($not*) and not global_legal_license } rule exploit_attempt: high { diff --git a/rules/impact/remote_access/backdoor.yara b/rules/impact/remote_access/backdoor.yara index 1a765860c..aae54b22f 100644 --- a/rules/impact/remote_access/backdoor.yara +++ b/rules/impact/remote_access/backdoor.yara @@ -1,14 +1,4 @@ -private rule wordlist { - strings: - $scorpion = "scorpion" - $superman = "superman" - $porsche = "porsche" - $cardinal = "cardinal" - $wombat = "wombat" - - condition: - filesize < 100MB and 3 of them -} +include "rules/global/global.yara" rule backdoor: medium { meta: @@ -22,7 +12,7 @@ rule backdoor: medium { $not_comment = "# backdoor:" condition: - filesize < 40MB and any of them and not wordlist and none of ($not*) + filesize < 40MB and any of them and not global_word_list and none of ($not*) } rule backdoor_shell: high { @@ -77,7 +67,7 @@ rule backdoor_caps: high { $ref2 = /[a-zA-Z\-_ \']{0,16}BACKDOOR[a-zA-Z\-_ ]{0,16}/ fullword condition: - filesize < 40MB and any of them and not wordlist + filesize < 40MB and any of them and not global_word_list } rule backdoor_leet: critical { @@ -88,7 +78,7 @@ rule backdoor_leet: critical { $ref4 = /[a-zA-Z\-_ \']{0,16}[bB][a4]ckd00r[a-zA-Z\-_ ]{0,16}/ condition: - filesize < 100MB and any of them and not wordlist + filesize < 100MB and any of them and not global_word_list } rule commands: high { @@ -104,11 +94,6 @@ rule commands: high { all of them } -private rule backdoor_small_macho { - condition: - filesize < 1MB 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 macho_backdoor_libc_signature: high { meta: description = "executes libc functions common to backdoors" @@ -150,7 +135,7 @@ rule macho_backdoor_libc_signature: high { $not_java = "java/lang" condition: - backdoor_small_macho and #word_with_spaces < 10 and #libc_call < 74 and 95 % of ($f*) and none of ($not*) + global_small_macho and #word_with_spaces < 10 and #libc_call < 74 and 95 % of ($f*) and none of ($not*) } rule minecraft_load_fetch_class_backdoor: critical { diff --git a/rules/impact/remote_access/py_setuptools.yara b/rules/impact/remote_access/py_setuptools.yara index 4e7213023..5078feb2c 100644 --- a/rules/impact/remote_access/py_setuptools.yara +++ b/rules/impact/remote_access/py_setuptools.yara @@ -1,25 +1,6 @@ import "math" -private rule remote_access_pythonSetup { - strings: - $if_distutils = /from distutils.core import .{0,32}setup/ - $if_setuptools = /from setuptools import .{0,32}setup/ - $i_setuptools = "import setuptools" - $setup = "setup(" - - $not_setup_example = ">>> setup(" - $not_setup_todict = "setup(**config.todict()" - $not_import_quoted = "\"from setuptools import setup" - $not_setup_quoted = "\"setup(name=" - $not_distutils = "from distutils.errors import" - - $not_hopper1 = "PACKAGE_NAME = \"flashattn-hopper\"" - $not_hopper2 = "check_if_cuda_home_none(\"--fahopper\")" - $not_hopper3 = "name=\"flashattn_hopper_cuda\"," - - condition: - filesize < 128KB and $setup and any of ($i*) in (0..1024) and none of ($not*) -} +include "rules/global/global.yara" rule setuptools_oslogin: medium { meta: @@ -30,7 +11,7 @@ rule setuptools_oslogin: medium { $oslogin = "os.login()" condition: - remote_access_pythonSetup and any of them + global_python_setup and any of them } rule setuptools_homedir: high { @@ -42,7 +23,7 @@ rule setuptools_homedir: high { $oslogin = "C:\\Users\\.{0,64}os.login()" condition: - remote_access_pythonSetup and any of them + global_python_setup and any of them } rule setuptools_cmd_exec: high { @@ -62,7 +43,7 @@ rule setuptools_cmd_exec: high { $not_twine_upload = "twine upload dist/*" condition: - remote_access_pythonSetup and any of ($f*) and none of ($not*) + global_python_setup and any of ($f*) and none of ($not*) } rule setuptools_cmd_exec_start: critical { @@ -77,7 +58,7 @@ rule setuptools_cmd_exec_start: critical { $f_subprocess = /subprocess.\w{0,32}\([f\"\']{0,2}start[,'" ]{1,3}.{0,64}/ condition: - remote_access_pythonSetup and any of ($f*) + global_python_setup and any of ($f*) } rule setuptools_eval: medium { @@ -89,7 +70,7 @@ rule setuptools_eval: medium { $f_eval = /eval\([\"\'\/\w\,\.\ \-\)\(]{1,64}\)/ fullword condition: - remote_access_pythonSetup and any of ($f*) + global_python_setup and any of ($f*) } rule setuptools_eval_high: high { @@ -102,7 +83,7 @@ rule setuptools_eval_high: high { $not_namespaced = /eval\([\w\.\(\)\"\/\']{4,16}, [a-z]{1,6}[,\)]/ condition: - remote_access_pythonSetup and any of ($f*) and none of ($not*) + global_python_setup and any of ($f*) and none of ($not*) } rule setuptools_exec: medium { @@ -116,7 +97,7 @@ rule setuptools_exec: medium { $not_hopper = "with open(\" hopper /__version__.py\") as fp:" condition: - remote_access_pythonSetup and any of ($f*) and none of ($not*) + global_python_setup and any of ($f*) and none of ($not*) } rule setuptools_exec_high: high { @@ -138,7 +119,7 @@ rule setuptools_exec_high: high { $not_namespaced = /exec\([\w\.\(\)\"\/\']{4,16}, [a-z]{1,6}[,\)]/ condition: - remote_access_pythonSetup and any of ($f*) and none of ($not*) + global_python_setup and any of ($f*) and none of ($not*) } rule setuptools_b64decode: suspicious { @@ -150,7 +131,7 @@ rule setuptools_b64decode: suspicious { $base64 = "b64decode" condition: - remote_access_pythonSetup and any of them + global_python_setup and any of them } rule setuptools_preinstall: suspicious { @@ -165,7 +146,7 @@ rule setuptools_preinstall: suspicious { $f_pre_install = "from pre_install" condition: - remote_access_pythonSetup and any of them + global_python_setup and any of them } rule setuptools_b64encode: suspicious { @@ -177,7 +158,7 @@ rule setuptools_b64encode: suspicious { $base64 = "b64encode" condition: - remote_access_pythonSetup and any of them + global_python_setup and any of them } rule setuptools_exec_powershell: critical windows { @@ -206,7 +187,7 @@ rule setuptools_os_path_exists: medium { $not_pyspark_ioerror = "\"Failed to load PySpark version file for packaging. You must be in Spark's python dir.\"" condition: - remote_access_pythonSetup and $ref and none of ($not*) + global_python_setup and $ref and none of ($not*) } rule setuptools_excessive_bitwise_math: critical { @@ -218,5 +199,5 @@ rule setuptools_excessive_bitwise_math: critical { $x = /\-{0,1}\d{1,8} \<\< \-{0,1}\d{1,8}/ condition: - remote_access_pythonSetup and #x > 20 + global_python_setup and #x > 20 } diff --git a/rules/impact/wipe/crypto.yara b/rules/impact/wipe/crypto.yara index 71d8670db..0bcc634ad 100644 --- a/rules/impact/wipe/crypto.yara +++ b/rules/impact/wipe/crypto.yara @@ -1,7 +1,4 @@ -private rule crypto_elf_or_macho { - condition: - uint32(0) == 1179403647 or (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) -} +include "rules/global/global.yara" rule uname_hostname_encrypt_wipe_kill_small: high { meta: @@ -17,7 +14,7 @@ rule uname_hostname_encrypt_wipe_kill_small: high { $hostname = "hostname" fullword condition: - filesize < 2MB and crypto_elf_or_macho and all of them + filesize < 2MB and global_elf_or_macho and all of them } rule uname_hostname_encrypt_wipe_kill: medium { @@ -34,5 +31,5 @@ rule uname_hostname_encrypt_wipe_kill: medium { $hostname = "hostname" fullword condition: - filesize < 20MB and crypto_elf_or_macho and all of them + filesize < 20MB and global_elf_or_macho and all of them } diff --git a/rules/malware/family/amos.yara b/rules/malware/family/amos.yara index 650f1ab93..a407aa987 100644 --- a/rules/malware/family/amos.yara +++ b/rules/malware/family/amos.yara @@ -1,14 +1,6 @@ import "math" -private rule amos_macho { - strings: - $not_jar = "META-INF/" - $not_dwarf = "_DWARF" - $not_kext = "_.SYMDEF SORTED" - - condition: - (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) and none of ($not*) -} +include "rules/global/global.yara" rule amos_magic_var: critical macos { meta: @@ -27,7 +19,7 @@ rule amos_magic_var: critical macos { $word_with_spaces = /[a-z]{2,} [a-z]{2,}/ condition: - filesize > 100KB and filesize < 600KB and amos_macho and $magic and $header and $main and all of ($f*) and #word_with_spaces < 3 + filesize > 100KB and filesize < 600KB and global_specific_macho and $magic and $header and $main and all of ($f*) and #word_with_spaces < 3 } rule amos_base32: critical macos { @@ -44,7 +36,7 @@ rule amos_base32: critical macos { $at_exit = "@___cxa_atexit" condition: - filesize > 40KB and filesize < 2MB and amos_macho and all of them + filesize > 40KB and filesize < 2MB and global_specific_macho and all of them } rule maybe_amos: high macos { @@ -66,7 +58,7 @@ rule maybe_amos: high macos { $not_release = "@_CFRelease" fullword condition: - filesize > 190KB and filesize < 400KB and amos_macho and all of them and none of ($not*) and math.entropy(1, filesize) >= 4 + filesize > 190KB and filesize < 400KB and global_specific_macho and all of them and none of ($not*) and math.entropy(1, filesize) >= 4 } rule maybe_amos_hex: high macos { @@ -90,5 +82,5 @@ rule maybe_amos_hex: high macos { $x = /0x[\dabcdefABCDEF]{2,8}/ condition: - filesize > 190KB and filesize < 400KB and amos_macho and 95 % of ($f*) and math.entropy(20000, 50000) >= 4.5 and #x > 64 + filesize > 190KB and filesize < 400KB and global_specific_macho and 95 % of ($f*) and math.entropy(20000, 50000) >= 4.5 and #x > 64 } diff --git a/rules/malware/family/clapzok.yara b/rules/malware/family/clapzok.yara index cda522a93..dbf5f836b 100644 --- a/rules/malware/family/clapzok.yara +++ b/rules/malware/family/clapzok.yara @@ -1,7 +1,4 @@ -private rule is_macho { - condition: - (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) -} +include "rules/global/global.yara" rule clapzok_macho: critical { meta: @@ -13,5 +10,5 @@ rule clapzok_macho: critical { $ref = "SfcIsFileProtected" condition: - filesize < 10MB and is_macho and $ref in (filesize - 2200..filesize - 100) + filesize < 10MB and global_specific_macho and $ref in (filesize - 2200..filesize - 100) } diff --git a/rules/malware/family/poseidon_stealer.yara b/rules/malware/family/poseidon_stealer.yara index 82952ffa5..59261c32d 100644 --- a/rules/malware/family/poseidon_stealer.yara +++ b/rules/malware/family/poseidon_stealer.yara @@ -1,14 +1,6 @@ import "math" -private rule poseidon_macho { - strings: - $not_jar = "META-INF/" - $not_dwarf = "_DWARF" - $not_kext = "_.SYMDEF SORTED" - - condition: - (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) and none of ($not*) -} +include "rules/global/global.yara" rule poseidon: high macos { meta: @@ -24,7 +16,7 @@ rule poseidon: high macos { $ve = "vector" fullword condition: - filesize > 190KB and filesize < 400KB and poseidon_macho and all of them and math.entropy(20000, 50000) >= 2.5 + filesize > 190KB and filesize < 400KB and global_specific_macho and all of them and math.entropy(20000, 50000) >= 2.5 } rule poseidon_url: high macos { @@ -37,5 +29,5 @@ rule poseidon_url: high macos { $ref = "https://forked-project.com/check_updates" condition: - filesize > 190KB and filesize < 400KB and poseidon_macho and all of them + filesize > 190KB and filesize < 400KB and global_specific_macho and all of them } diff --git a/rules/net/download/fetch.yara b/rules/net/download/fetch.yara index 0ffa22c31..91c5788c3 100644 --- a/rules/net/download/fetch.yara +++ b/rules/net/download/fetch.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule curl_value: medium { meta: description = "Invokes curl" @@ -76,16 +78,6 @@ rule curl_download_ip: critical { any of them } -private rule fetch_macho { - condition: - uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178 -} - -private rule fetch_elf { - condition: - uint32(0) == 1179403647 -} - rule fetch_tool: medium { meta: description = "calls a URL fetch tool" @@ -117,7 +109,7 @@ rule binary_calls_fetch_tool: high { $not_tftp_err = "tftp error" condition: - filesize < 10MB and (fetch_elf or fetch_macho) and any of ($t*) and none of ($not*) + filesize < 10MB and (global_elf_or_macho) and any of ($t*) and none of ($not*) } rule curl_agent_val: high { diff --git a/rules/sus/compiler.yara b/rules/sus/compiler.yara index 08a18b2f7..111053000 100644 --- a/rules/sus/compiler.yara +++ b/rules/sus/compiler.yara @@ -1,3 +1,5 @@ +include "rules/global/global.yara" + rule archaic_gcc: medium { meta: description = "built by an ancient version of GCC" @@ -28,12 +30,6 @@ rule small_opaque_archaic_gcc: high linux { filesize < 30KB and $gcc_v4 and $fork in (1000..3000) and none of ($not*) and #word_with_spaces < 15 } -private rule binary { - condition: - // matches ELF or machO binary - filesize < 40MB and (uint32(0) == 1179403647 or uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962) -} - rule multiple_gcc: medium { meta: description = "built with multiple versions of GCC" @@ -43,7 +39,7 @@ rule multiple_gcc: medium { $gcc = /GCC: \([\w \.\-\~\(\)]{8,64}/ fullword condition: - binary and #gcc > 1 and !gcc[1] != !gcc[2] + global_binary and #gcc > 1 and !gcc[1] != !gcc[2] } rule multiple_gcc_high: high { @@ -58,5 +54,5 @@ rule multiple_gcc_high: high { $not_java = "JAVA_HOME" condition: - binary and #gcc > 1 and !gcc[1] != !gcc[2] and none of ($not*) + global_binary and #gcc > 1 and !gcc[1] != !gcc[2] and none of ($not*) } diff --git a/rules/sus/entitlement.yara b/rules/sus/entitlement.yara index ca2e4ba68..a491e2416 100644 --- a/rules/sus/entitlement.yara +++ b/rules/sus/entitlement.yara @@ -1,12 +1,4 @@ -private rule entitlement_macho { - strings: - $not_jar = "META-INF/" - $not_dwarf = "_DWARF" - $not_kext = "_.SYMDEF SORTED" - - condition: - (uint32(0) == 4277009102 or uint32(0) == 3472551422 or uint32(0) == 4277009103 or uint32(0) == 3489328638 or uint32(0) == 3405691582 or uint32(0) == 3199925962 or uint32(0) == 3405691583 or uint32(0) == 3216703178) and none of ($not*) -} +include "rules/global/global.yara" rule com_apple_get_task_allow: medium { meta: @@ -18,5 +10,5 @@ rule com_apple_get_task_allow: medium { $true = "" condition: - entitlement_macho and all of them + global_specific_macho and all of them } diff --git a/tests/python/2024.coloredtxt/base64_payload3.py.simple b/tests/python/2024.coloredtxt/base64_payload3.py.simple index 3a290cc7c..0c2179029 100644 --- a/tests/python/2024.coloredtxt/base64_payload3.py.simple +++ b/tests/python/2024.coloredtxt/base64_payload3.py.simple @@ -1,5 +1,6 @@ # python/2024.coloredtxt/base64_payload3.py: critical c2/addr/url: high +c2/tool_transfer/python: high data/base64/decode: medium data/encoding/base64: low discover/system/platform: medium diff --git a/tests/python/clean/hatch/migrate.py.simple b/tests/python/clean/hatch/migrate.py.simple index 448d31422..bb81c619b 100644 --- a/tests/python/clean/hatch/migrate.py.simple +++ b/tests/python/clean/hatch/migrate.py.simple @@ -2,11 +2,11 @@ discover/system/environment: medium exec/imports/python: low exec/program: medium -false-positives/py_hatch: low fs/directory/list: low fs/file/open: low fs/symlink_resolve: low fs/tempdir/TEMP: low +impact/remote_access/py_setuptools: medium net/download: medium os/env/get: low os/fd/read: low diff --git a/tests/python/clean/setuptools/namespaces.py.simple b/tests/python/clean/setuptools/namespaces.py.simple index 28aedf1ae..6f9e2b1a8 100644 --- a/tests/python/clean/setuptools/namespaces.py.simple +++ b/tests/python/clean/setuptools/namespaces.py.simple @@ -1,5 +1,5 @@ # python/clean/setuptools/namespaces.py: low data/encoding/json_encode: low exec/imports/python: low -false-positives/setuptools: low fs/directory/create: low +impact/remote_access/py_setuptools: low