-
Notifications
You must be signed in to change notification settings - Fork 71
Add extensions ecosystem support for Guarddog #589
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
Changes from 5 commits
64d915d
4bce5bd
8e2cd4a
2564a61
1fdda88
54b72e3
e39c0ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,8 @@ | |
|
|
||
|
|
||
| # These data class aim to reduce the spreading of the logic | ||
| # Instead of using the a dict as a structure and parse it difffently depending on the type | ||
| # Instead of using the a dict as a structure and parse it difffently | ||
| # depending on the type | ||
| @dataclass | ||
| class SourceCodeRule: | ||
| """ | ||
|
|
@@ -22,6 +23,7 @@ class SourceCodeRule: | |
| id: str | ||
| file: str | ||
| description: str | ||
| ecosystem: Optional[ECOSYSTEM] # None means "any ecosystem" | ||
|
|
||
|
|
||
| @dataclass | ||
|
|
@@ -38,13 +40,11 @@ class SempgrepRule(SourceCodeRule): | |
| Semgrep rule are language specific | ||
| Content of rule in yaml format is accessible through rule_content | ||
| """ | ||
| ecosystem: ECOSYSTEM | ||
| rule_content: dict | ||
|
|
||
|
|
||
| def get_sourcecode_rules( | ||
| ecosystem: ECOSYSTEM, kind: Optional[type] = None | ||
| ) -> Iterable[SourceCodeRule]: | ||
| ecosystem: ECOSYSTEM, kind: Optional[type] = None) -> Iterable[SourceCodeRule]: | ||
| """ | ||
| This function returns the source code rules for a given ecosystem and kind. | ||
| Args: | ||
|
|
@@ -54,7 +54,8 @@ def get_sourcecode_rules( | |
| for rule in SOURCECODE_RULES: | ||
| if kind and not isinstance(rule, kind): | ||
| continue | ||
| if not (getattr(rule, "ecosystem", ecosystem) == ecosystem): | ||
| # Include rules that match the specific ecosystem OR rules that apply to any ecosystem (None) | ||
| if rule.ecosystem is not None and rule.ecosystem != ecosystem: | ||
| continue | ||
| yield rule | ||
|
|
||
|
|
@@ -78,13 +79,15 @@ def get_sourcecode_rules( | |
| case "javascript" | "typescript" | "json": | ||
| ecosystems.add(ECOSYSTEM.NPM) | ||
| ecosystems.add(ECOSYSTEM.GITHUB_ACTION) | ||
| ecosystems.add(ECOSYSTEM.EXTENSION) | ||
tesnim5hamdouni marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| case "go": | ||
| ecosystems.add(ECOSYSTEM.GO) | ||
| case _: | ||
| continue | ||
|
|
||
| for ecosystem in ecosystems: | ||
| # avoids duplicates when multiple languages are supported by a rule | ||
| # avoids duplicates when multiple languages are supported | ||
| # by a rule | ||
| if not next( | ||
| filter( | ||
| lambda r: r.id == rule["id"], | ||
|
|
@@ -99,8 +102,7 @@ def get_sourcecode_rules( | |
| description=rule.get("metadata", {}).get("description", ""), | ||
| file=file_name, | ||
| rule_content=rule, | ||
| ) | ||
| ) | ||
| )) | ||
|
|
||
| yara_rule_file_names = list( | ||
| filter(lambda x: x.endswith("yar"), os.listdir(current_dir)) | ||
|
|
@@ -111,9 +113,23 @@ def get_sourcecode_rules( | |
| rule_id = pathlib.Path(file_name).stem | ||
| description_regex = fr'\s*rule\s+{rule_id}[^}}]+meta:[^}}]+description\s*=\s*\"(.+?)\"' | ||
|
|
||
| # Determine ecosystem based on filename prefix | ||
| rule_ecosystem: Optional[ECOSYSTEM] | ||
| if file_name.startswith("extension_"): | ||
| rule_ecosystem = ECOSYSTEM.EXTENSION | ||
| else: | ||
| # If no specific ecosystem prefix, apply to any ecosystem | ||
| rule_ecosystem = None | ||
|
||
|
|
||
| with open(os.path.join(current_dir, file_name), "r") as fd: | ||
| match = re.search(description_regex, fd.read()) | ||
| rule_description = "" | ||
| if match: | ||
| rule_description = match.group(1) | ||
| SOURCECODE_RULES.append(YaraRule(id=rule_id, file=file_name, description=rule_description)) | ||
|
|
||
| SOURCECODE_RULES.append(YaraRule( | ||
| id=rule_id, | ||
| file=file_name, | ||
| description=rule_description, | ||
| ecosystem=rule_ecosystem | ||
| )) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| rule DETECT_FILE_powershell_policy_bypass | ||
| { | ||
| meta: | ||
| author = "T HAMDOUNI, Datadog" | ||
| credits = "" | ||
|
||
| description = "Detects suspicious read access to /etc/passwd file, which is often targeted by malware for credential harvesting" | ||
|
|
||
| strings: | ||
| $cli = /(cat|less|more|head|tail)\s+.{0,100}\/etc\/passwd/ nocase | ||
| $read = /(readFile|readFileSync)\(\s*['"]\/etc\/passwd/ nocase | ||
| condition: | ||
| $cli or $read | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| rule DETECT_FILE_suspicious_passwd_access_linux | ||
| { | ||
| meta: | ||
| author = "T HAMDOUNI, Datadog" | ||
| credits = "" | ||
|
||
| description = "Detects suspicious read access to /etc/passwd file, which is often targeted by malware for credential harvesting" | ||
|
|
||
| strings: | ||
| $cli = /(cat|less|more|head|tail)\s+.{0,100}\/etc\/passwd/ nocase | ||
| $read = /(readFile|readFileSync)\(\s*['"]\/etc\/passwd/ nocase | ||
| condition: | ||
| $cli or $read | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
| from .go_package_scanner import GoModuleScanner | ||
| from .go_project_scanner import GoDependenciesScanner | ||
| from .github_action_scanner import GithubActionScanner | ||
| from .extension_scanner import ExtensionScanner | ||
| from .scanner import PackageScanner, ProjectScanner | ||
| from ..ecosystems import ECOSYSTEM | ||
|
|
||
|
|
@@ -33,6 +34,8 @@ def get_package_scanner(ecosystem: ECOSYSTEM) -> Optional[PackageScanner]: | |
| return GoModuleScanner() | ||
| case ECOSYSTEM.GITHUB_ACTION: | ||
| return GithubActionScanner() | ||
| case ECOSYSTEM.EXTENSION: | ||
| return ExtensionScanner() | ||
| return None | ||
|
|
||
|
|
||
|
|
@@ -57,4 +60,6 @@ def get_project_scanner(ecosystem: ECOSYSTEM) -> Optional[ProjectScanner]: | |
| return GoDependenciesScanner() | ||
| case ECOSYSTEM.GITHUB_ACTION: | ||
| return GitHubActionDependencyScanner() | ||
| case ECOSYSTEM.EXTENSION: | ||
| return None # we're not including dependency scanning for this PR | ||
|
Comment on lines
+63
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. was this suggested by the lint? is adding no value |
||
| return None | ||
Uh oh!
There was an error while loading. Please reload this page.