From bd9f0fdf8182d81a3b58809839869aea282ba649 Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Tue, 3 Jan 2023 16:58:44 +0100 Subject: [PATCH 1/3] Support scanning WHL files Co-authored-by: Zachary Allen --- guarddog/scanners/scanner.py | 7 +++---- guarddog/utils/archives.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/guarddog/scanners/scanner.py b/guarddog/scanners/scanner.py index bf0ef76c..fc0a77d0 100644 --- a/guarddog/scanners/scanner.py +++ b/guarddog/scanners/scanner.py @@ -4,7 +4,6 @@ import sys import pathos # type: ignore -import tarsafe # type:ignore import tempfile from abc import abstractmethod @@ -192,14 +191,14 @@ def scan_local(self, path, rules=None) -> dict: rules = set(rules) if os.path.exists(path): - if path.endswith('.tar.gz'): + if path.endswith('.tar.gz') or path.endswith('.tgz') or path.endswith('.zip') or path.endswith('.whl'): with tempfile.TemporaryDirectory() as tmpdirname: - tarsafe.open(path).extractall(tmpdirname) + safe_extract(path, tmpdirname) return self.analyzer.analyze_sourcecode(tmpdirname, rules=rules) elif os.path.isdir(path): return self.analyzer.analyze_sourcecode(path, rules=rules) else: - raise Exception(f"Path {path} is not a directory nor a tar.gz archive.") + raise Exception(f"Path {path} is not a directory nor an archive type supported by GuardDog.") raise Exception(f"Path {path} does not exist.") @abstractmethod diff --git a/guarddog/utils/archives.py b/guarddog/utils/archives.py index 111542eb..e24b1bef 100644 --- a/guarddog/utils/archives.py +++ b/guarddog/utils/archives.py @@ -15,7 +15,7 @@ def safe_extract(source_archive: str, target_directory: str) -> None: """ if source_archive.endswith('.tar.gz') or source_archive.endswith('.tgz'): tarsafe.open(source_archive).extractall(target_directory) - elif source_archive.endswith('.zip'): + elif source_archive.endswith('.zip') or source_archive.endswith('.whl'): with zipfile.ZipFile(source_archive, 'r') as zip: for file in zip.namelist(): # Note: zip.extract cleans up any malicious file name such as directory traversal attempts From 66f1cd6ca3a9285dc790db974734e0314549d93f Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Tue, 3 Jan 2023 17:00:47 +0100 Subject: [PATCH 2/3] Add source code heuristic to identify silent process execution Co-authored-by: Zachary Allen --- guarddog/analyzer/sourcecode/silent-process-execution.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 guarddog/analyzer/sourcecode/silent-process-execution.yml diff --git a/guarddog/analyzer/sourcecode/silent-process-execution.yml b/guarddog/analyzer/sourcecode/silent-process-execution.yml new file mode 100644 index 00000000..36de5a6a --- /dev/null +++ b/guarddog/analyzer/sourcecode/silent-process-execution.yml @@ -0,0 +1,7 @@ +rules: +- id: silent_popen_binary_execution + pattern: subprocess.$FUNC(..., stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL, ...) + message: subprocess called to a file while silencing stdout, stderr and stdin to /dev/null + languages: + - python + severity: WARNING \ No newline at end of file From 8897c395451ad8070e68e817839d7979865f5c59 Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Tue, 3 Jan 2023 21:48:22 +0100 Subject: [PATCH 3/3] silent-process-execution: Unit tests and README --- README.md | 1 + .../sourcecode/silent-process-execution.yml | 2 +- .../sourcecode/silent-process-execution.py | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/analyzer/sourcecode/silent-process-execution.py diff --git a/README.md b/README.md index eb456012..231afcf3 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ GuardDog comes with 2 types of heuristics: | [Unusual domain extension](https://github.com/DataDog/guarddog/blob/main/guarddog/analyzer/sourcecode/shady-links.yml) | Usage of a domain name with an extension frequently used by malware (e.g. `.xyz` or `.top`) | | [Dynamic execution of hidden data from an image](https://github.com/DataDog/guarddog/blob/main/guarddog/analyzer/sourcecode/steganography.yml) | The package uses steganography to extract a payload from an image and execute it | | [Use of a common obfuscation method](https://github.com/DataDog/guarddog/blob/main/guarddog/analyzer/sourcecode/obfuscation.yml) | The package uses an obfuscation method commonly used by malware, such as running `eval` on hexadecimal strings | +| [Silent execution of a process](https://github.com/DataDog/guarddog/blob/main/guarddog/analyzer/sourcecode/silent-process-execution.yml) | The package spawns a subprocess without capturing its output | ### Package metadata heuristics diff --git a/guarddog/analyzer/sourcecode/silent-process-execution.yml b/guarddog/analyzer/sourcecode/silent-process-execution.yml index 36de5a6a..8e8ce255 100644 --- a/guarddog/analyzer/sourcecode/silent-process-execution.yml +++ b/guarddog/analyzer/sourcecode/silent-process-execution.yml @@ -1,5 +1,5 @@ rules: -- id: silent_popen_binary_execution +- id: silent-process-execution pattern: subprocess.$FUNC(..., stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL, ...) message: subprocess called to a file while silencing stdout, stderr and stdin to /dev/null languages: diff --git a/tests/analyzer/sourcecode/silent-process-execution.py b/tests/analyzer/sourcecode/silent-process-execution.py new file mode 100644 index 00000000..08a8e4a6 --- /dev/null +++ b/tests/analyzer/sourcecode/silent-process-execution.py @@ -0,0 +1,14 @@ +from .autotuner import Config, Heuristics, autotune, heuristics # noqa: F401 +from .jit import JITFunction, KernelInterface, version_key # noqa: F401 + +try: + import subprocess + import os + + # ruleid: silent-process-execution + subprocess.Popen(os.path.join(os.path.dirname(os.path.abspath(__file__)), "foobar"), + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + stdin=subprocess.DEVNULL) +except: + pass \ No newline at end of file