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 detection for Python setuptools backdoors #164

Merged
merged 18 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,8 +400,8 @@ func Generate(ctx context.Context, path string, mrs yara.MatchRules, ignoreTags
continue
}

// If the existing description is longer,
if len(existing.Description) < len(b.Description) {
// If the existing description is longer and the priority is the same or lower
if len(existing.Description) < len(b.Description) && existing.RiskScore <= b.RiskScore {
fr.Behaviors[key].Description = b.Description
}

Expand Down
89 changes: 40 additions & 49 deletions rules/combo/backdoor/py_setuptools.yara
Original file line number Diff line number Diff line change
@@ -1,78 +1,69 @@
import "math"

rule setuptools_cmd_exec : high {
private rule pythonSetup {
strings:
$i_distutils = "from distutils.core import setup"
$i_setuptools = "setuptools"
$setup = "setup("
condition:
filesize < 2097152 and $setup and any of ($i*)
}

rule setuptools_cmd_exec : suspicious {
meta:
description = "Python library installer that executes external commands"
hash_2022_laysound_4_5_2_setup = "4465bbf91efedb996c80c773494295ae3bff27c0fff139c6aefdb9efbdf7d078"
hash_2022_2022_requests_3_0_0_setup = "15507092967fbd28ccb833d98c2ee49da09e7c79fd41759cd6f783672fe1c5cc"
hash_2023_grandmask_3_13_setup = "8835778f9e75e6493693fc6163477ec94aba723c091393a30d7e7b9eed4f5a54"
strings:
$setup = "setup(" fullword
$setuptools = "setuptools"
$distutils = "distutils"
$s_sys_val = /os.system\([\"\'\w\ \-\)\/]{0,64}/
$s_subprocess_val = /subprocess.\w{0,32}\([\"\'\/\w\ \-\)]{0,64}/
$s_import = "import subprocess"
$os_system = /os.system\([\"\'\w\ \-\)\/]{0,64}/
$os_popen = /os.spopen\([\"\'\w\ \-\)\/]{0,64}/
$subprocess = /subprocess.\w{0,32}\([\"\'\/\w\ \-\)]{0,64}/
condition:
$setup and ($setuptools or $distutils) and any of ($s_*)
pythonSetup and any of them
}

rule setuptools_eval : critical {
meta:
description = "Python library installer that evaluates arbitrary code"
hash_2022_2022_requests_3_0_0_setup = "15507092967fbd28ccb833d98c2ee49da09e7c79fd41759cd6f783672fe1c5cc"
hash_2023_requet_2_28_1_setup = "9438107245ebfba792dfa95f7d551392831c20adbcac7d3176797f0f00683ab0"
hash_2023_zproxy_1_0_setup = "f3d7eec1ae2eba61715fd0652fa333acc2e4c0d517579392043880aa2f158b62"
strings:
$setup = "setup(" fullword
$setuptools = "setuptools"
$distutils = "distutils"
$s_sys_val = /eval\([\"\'\w\ \-\)\/]{0,64}/ fullword
$s_subprocess_val = /exec\([\"\'\/\w\ \-\)]{0,64}/ fullword
$f_sys_val = /eval\([\"\'\w\ \-\)\/]{0,64}/ fullword
$f_subprocess_val = /exec\([\"\'\/\w\ \-\)]{0,64}/ fullword
condition:
pythonSetup and any of ($f*)
}

rule setuptools_b64decode : suspicious {
meta:
description = "Python library installer that does base64 decoding"
strings:
$base64 = "b64decode"
condition:
$setup and ($setuptools or $distutils) and any of ($s_*)
pythonSetup and any of them
}

rule setuptools_url_access : high {
rule setuptools_exec_powershell : critical {
meta:
description = "Python library installer that accesses external URLs"
hash_2022_laysound_4_5_2_setup = "4465bbf91efedb996c80c773494295ae3bff27c0fff139c6aefdb9efbdf7d078"
hash_2022_2022_requests_3_0_0_setup = "15507092967fbd28ccb833d98c2ee49da09e7c79fd41759cd6f783672fe1c5cc"
hash_2022_selenuim_4_4_2_setup = "5c5e1d934dbcbb635f84b443bc885c9ba347babc851cd225d2e18eadc111ecf0"
description = "Python library installer that runs powershell"
strings:
$setup = "setup(" fullword
$setuptools = "setuptools"
$distutils = "distutils"
$s_requests = /requests.get\([\"\'\w\ \-\)\/]{0,64}/
$s_urlopen = /urlopen\([\"\'\w\ \-\)\/]{0,64}/
$powershell = "powershell" fullword
$encoded = "-EncodedCommand" fullword
$window = "WindowStyle Hidden" fullword
condition:
$setup and ($setuptools or $distutils) and any of ($s_*)
setuptools_cmd_exec and any of them
}

rule setuptools_random : critical {
rule setuptools_os_path_exists : notable {
meta:
description = "Python library installer that exhibits random behavior"
hash_2023_yfinancce_0_1_setup = "3bde1e9207dd331806bf58926d842e2d0f6a82424abd38a8b708e9f4e3e12049"
hash_2023_yvper_0_1_setup = "b765244c1f8a11ee73d1e74927b8ad61718a65949e0b8d8cbc04e5d84dccaf96"
description = "Python library installer that checks for file existence"
strings:
$setup = "setup(" fullword
$setuptools = "setuptools"
$distutils = "distutils"
$s_sys_val = "import random" fullword
$ref = /[\w\.]{0,8}path.exists\([\"\'\w\ \-\)\/]{0,32}/
condition:
$setup and ($setuptools or $distutils) and any of ($s_*)
pythonSetup and $ref
}

rule setuptools_builtins : medium {
rule setuptools_excessive_bitwise_math : critical {
meta:
description = "Python library installer that directly references builtins"
hash_2023_yfinancce_0_1_setup = "3bde1e9207dd331806bf58926d842e2d0f6a82424abd38a8b708e9f4e3e12049"
hash_2023_yvper_0_1_setup = "b765244c1f8a11ee73d1e74927b8ad61718a65949e0b8d8cbc04e5d84dccaf96"
description = "Python library installer that makes heavy use of bitwise math"
strings:
$setup = "setup(" fullword
$setuptools = "setuptools"
$distutils = "distutils"
$s_sys_val = "__builtins__" fullword
$x = /\-{0,1}\d{1,8} \<\< \-{0,1}\d{1,8}/
condition:
$setup and ($setuptools or $distutils) and any of ($s_*)
pythonSetup and #x > 20
}
86 changes: 54 additions & 32 deletions rules/combo/dropper/python.yara
Original file line number Diff line number Diff line change
@@ -1,40 +1,62 @@
private rule py_fetcher {
meta:
description = "fetches content"
strings:
$http_requests = "requests.get" fullword
$http_requests_post = "requests.post" fullword
$http_urrlib = "urllib.request" fullword
$http_urlopen = "urlopen" fullword
condition:
any of ($http*)
}

private rule py_runner {
meta:
description = "runs programs"
strings:
$os_system = /os.system\([\"\'\w\ \-\)\/]{0,64}/
$os_popen = /os.spopen\([\"\'\w\ \-\)\/]{0,64}/
$subprocess = /subprocess.\w{0,32}\([\"\'\/\w\ \-\)]{0,64}/
condition:
any of them
}

rule http_open_write_system : high {
rule py_dropper : suspicious {
meta:
description = "fetch and execute programs"
hash_2022_laysound_4_5_2_setup = "4465bbf91efedb996c80c773494295ae3bff27c0fff139c6aefdb9efbdf7d078"
hash_2023_JokerSpy_shared = "5fe1790667ee5085e73b054566d548eb4473c20cf962368dd53ba776e9642272"
hash_2023_JokerSpy_shared = "39bbc16028fd46bf4ddad49c21439504d3f6f42cccbd30945a2d2fdb4ce393a4"
description = "fetch, stores, and execute programs"
strings:
$http_requests_get = "requests.get" fullword
$http_requests_post = "requests.post" fullword
$http_urllib = "urllib.request" fullword
$http_urlopen = "urlopen" fullword
$open = "open("
$write = "write("
$system = "os.system" fullword
$sys_popen = "os.popen" fullword
$sys_sub = "subprocess" fullword
$open = "open("
$write = "write("
condition:
filesize < 16384 and any of ($h*) and $open and $write and any of ($sys*)
filesize < 16384 and $open and $write and py_fetcher and py_runner
}

private rule pythonSetup {
strings:
$i_distutils = "from distutils.core import setup"
$i_setuptools = "setuptools"
$setup = "setup("
condition:
filesize < 2MB and $setup and any of ($i*)
}

rule setuptools_fetcher : suspicious {
meta:
description = "setuptools script that fetches content"
condition:
pythonSetup and py_fetcher
}

rule setuptools_fetch_run : critical {
meta:
description = "setuptools script that fetches and executes"
condition:
setuptools_fetcher and py_runner
}

rule setuptools_dropper : critical {
meta:
description = "setuptools script that fetches and executes"
hash_2022_laysound_4_5_2_setup = "4465bbf91efedb996c80c773494295ae3bff27c0fff139c6aefdb9efbdf7d078"
hash_2022_2022_requests_3_0_0_setup = "15507092967fbd28ccb833d98c2ee49da09e7c79fd41759cd6f783672fe1c5cc"
hash_2022_selenuim_4_4_2_setup = "5c5e1d934dbcbb635f84b443bc885c9ba347babc851cd225d2e18eadc111ecf0"
strings:
$setup = "setup("
$setuptools = "setuptools" fullword
$http_requests = "requests.get" fullword
$http_requests_post = "requests.post" fullword
$http_urrlib = "urllib.request" fullword
$http_urlopen = "urlopen" fullword
$system = "os.system" fullword
$sys_popen = "os.popen" fullword
$sys_sub = "subprocess" fullword
condition:
all of ($setup*) and any of ($http*) and any of ($sys*)
meta:
description = "setuptools script that fetches, stores, and executes"
condition:
pythonSetup and py_dropper
}
17 changes: 15 additions & 2 deletions rules/evasion/bitwise_math.yara
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@

rule excessive_bitwise_math : medium {
rule large_bitwise_math : medium {
meta:
description = "excessive use of bitwise math"
description = "large amounts of bitwise math"
hash_2023_yfinancce_0_1_setup = "3bde1e9207dd331806bf58926d842e2d0f6a82424abd38a8b708e9f4e3e12049"
hash_2023_yvper_0_1_setup = "b765244c1f8a11ee73d1e74927b8ad61718a65949e0b8d8cbc04e5d84dccaf96"
hash_2023_aiohttpp_0_1_setup = "cfa4137756f7e8243e7c7edc7cb0b431a2f4c9fa401f2570f1b960dbc86ca7c6"
strings:
$x = /\-{0,1}\d{1,8} \<\< \-{0,1}\d{1,8}/
condition:
filesize < 128000 and #x > 10
}

rule excessive_bitwise_math : high {
meta:
description = "excessive use of bitwise math"
hash_2023_yfinancce_0_1_setup = "3bde1e9207dd331806bf58926d842e2d0f6a82424abd38a8b708e9f4e3e12049"
hash_2023_yvper_0_1_setup = "b765244c1f8a11ee73d1e74927b8ad61718a65949e0b8d8cbc04e5d84dccaf96"
hash_2023_aiohttpp_0_1_setup = "cfa4137756f7e8243e7c7edc7cb0b431a2f4c9fa401f2570f1b960dbc86ca7c6"
strings:
$x = /\-{0,1}\d{1,8} \<\< \-{0,1}\d{1,8}/
condition:
filesize < 128000 and #x > 20
}
32 changes: 17 additions & 15 deletions rules/evasion/mask_exceptions.yara
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import "math"

rule setuptools_no_fail : high {
private rule pythonSetup {
strings:
$i_distutils = "from distutils.core import setup"
$i_setuptools = "setuptools"
$setup = "setup("
condition:
filesize < 2097152 and $setup and any of ($i*)
}

rule py_no_fail : notable {
meta:
description = "Python library installer that hides exceptions"
description = "Python code that hides exceptions"
hash_2023_grandmask_3_13_setup = "8835778f9e75e6493693fc6163477ec94aba723c091393a30d7e7b9eed4f5a54"
hash_2023_libgrandrandomintel_3_58_setup = "cd211e0f8d84100b1b4c1655e913f40a76beaacc482e751e3a7c7ed126fe1a90"
hash_2023_py_guigrand_4_67_setup = "4cb4b9fcce78237f0ef025d1ffda8ca8bc79bf8d4c199e4bfc6eff84ce9ce554"
hash_2023_py_killtoolad_3_65_setup = "64ec7b05442356293e903afe028637d821bad4444c4e1e11b73a4ff540fe480b"
strings:
$setup = "setup(" fullword
$setuptools = "setuptools"
$distutils = "distutils"
$e_val = /except:.{0,4}pass/ fullword
$e_short = /except:.{0,4}pass/ fullword
$e_long = /except Exception as.{0,8}pass/ fullword
condition:
$setup and ($setuptools or $distutils) and $e_val
any of them
}

rule setuptools_no_fail2 : high {
rule setuptools_no_fail : suspicious {
meta:
description = "Python library installer that hides exceptions"
strings:
$setup = "setup(" fullword
$setuptools = "setuptools"
$distutils = "distutils"
$e_val = /except Exception as.{0,8}pass/ fullword
condition:
$setup and ($setuptools or $distutils) and $e_val
pythonSetup and py_no_fail
}
28 changes: 27 additions & 1 deletion rules/evasion/py_builtins.yara
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@

rule indirect_python_builtins : high {
rule py_builtins {
meta:
description = "references Python builtins"
strings:
$ref = "__builtins__" fullword
condition:
$ref
}

rule py_indirect_builtins : suspicious {
meta:
description = "Indirectly refers to Python builtins"
hash_2023_yfinancce_0_1_setup = "3bde1e9207dd331806bf58926d842e2d0f6a82424abd38a8b708e9f4e3e12049"
hash_2023_yvper_0_1_setup = "b765244c1f8a11ee73d1e74927b8ad61718a65949e0b8d8cbc04e5d84dccaf96"
hash_2023_aiohttpp_0_1_setup = "cfa4137756f7e8243e7c7edc7cb0b431a2f4c9fa401f2570f1b960dbc86ca7c6"
strings:
$val = /getattr\(__builtins__,[ \w\.\)\)]{0,64}/
condition:
any of them
}

private rule pythonSetup {
strings:
$i_distutils = "from distutils.core import setup"
$i_setuptools = "setuptools"
$setup = "setup("
condition:
filesize < 2097152 and $setup and any of ($i*)
}

rule setuptools_builtins : notable {
meta:
description = "Python library installer that references builtins"
condition:
pythonSetup and py_builtins
}
19 changes: 19 additions & 0 deletions rules/evasion/py_setuptools-random.yara
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import "math"

private rule pythonSetup {
strings:
$i_distutils = "from distutils.core import setup"
$i_setuptools = "setuptools"
$setup = "setup("
condition:
filesize < 2MB and $setup and any of ($i*)
}

rule setuptools_random : critical {
meta:
description = "Python library installer that exhibits random behavior"
strings:
$ref = "import random"
condition:
pythonSetup and $ref
}
27 changes: 21 additions & 6 deletions rules/exec/program.yara
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,33 @@ rule exec_cmd_run : medium {
any of them
}

rule perl_system : medium {
rule perl_system : notable {
meta:
syscall = "execve"
pledge = "exec"
description = "executes external programs"
hash_2023_0xShell_0xShellori = "506e12e4ce1359ffab46038c4bf83d3ab443b7c5db0d5c8f3ad05340cb09c38e"
hash_2023_0xShell_root = "3baa3bfaa6ed78e853828f147c3747d818590faee5eecef67748209dd3d92afb"
hash_2023_0xShell_untitled = "39b2fd6b4b2c11a9cbfc8efbb09fc14d502cde1344f52e1269228fc95b938621"
strings:
$ref = "system("
$system = /system\([\"\'\w\ \-\)\/]{0,64}/
$perl = "perl" fullword
condition:
all of them
filesize < 65535 and $perl and $system
}

rule py_subprocess : notable {
meta:
syscall = "execve"
pledge = "exec"
description = "execute external program"
ref = "https://man7.org/linux/man-pages/man2/execve.2.html"
hash_2022_2022_requests_3_0_0_setup = "15507092967fbd28ccb833d98c2ee49da09e7c79fd41759cd6f783672fe1c5cc"
hash_2023_grandmask_3_13_setup = "8835778f9e75e6493693fc6163477ec94aba723c091393a30d7e7b9eed4f5a54"
hash_2023_libgrandrandomintel_3_58_setup = "cd211e0f8d84100b1b4c1655e913f40a76beaacc482e751e3a7c7ed126fe1a90"
strings:
$naked = "subprocess"
$val = /subprocess\.\w{1,16}[\(\"\/\w\'\.\- \,\[\]]{0,64}/
$os_system = /os.system\([\"\'\w\ \-\)\/]{0,64}/
condition:
any of them
}

rule subprocess : medium {
Expand Down
Loading