Skip to content

Commit

Permalink
Improve detection for Python setuptools backdoors (#164)
Browse files Browse the repository at this point in the history
* Improve reliability of py_setuptools rules

* Fix GoReleaser (#162)

* Fix GoReleaser

* Add project_name

* Remove problematic MS repository from Checks

* Repository has been fixed

* Import rule URLs, add them to markdown & JSON output (#165)

* Add URLs to markdown output

* run prettier against output

* Disable or modify GitHub actions to work better with third_party code (#152)

* Bump actions/checkout from 4.1.3 to 4.1.4 in the all group (#171)

Bumps the all group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 4.1.3 to 4.1.4
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@1d96c77...0ad4b8f)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Add ThreatHunting-Keywords-yara-rules (#160)

* Add ThreatHunting-Keywords-yara-rules

* Update README

* Remove superfluous mkdir command

* Fix tests

* Fix tests

* Remove merge artifacts

* Pin rules to a known commit; add check for updates

* Re-add -s

* Avoid using jq for portability

* Add new commit to output

* Fix test

* Bump golangci/golangci-lint-action from 4.0.0 to 5.0.0 (#172)

Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 4.0.0 to 5.0.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](golangci/golangci-lint-action@3cfe3a4...82d40c2)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Thomas Strömberg <t+github@chainguard.dev>
Co-authored-by: Ville Aikas <11279988+vaikas@users.noreply.github.com>

* Improve how we approach Python code

* Add 2021.DiscordSafety sample

* Make pythonSetup private again

* Add aiohttp sample

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Evan Gibler <keybase@egibs.xyz>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ville Aikas <11279988+vaikas@users.noreply.github.com>
  • Loading branch information
4 people committed May 13, 2024
1 parent bdcd078 commit 5a95dc0
Show file tree
Hide file tree
Showing 14 changed files with 398 additions and 107 deletions.
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

0 comments on commit 5a95dc0

Please sign in to comment.