Skip to content

Commit 749b9e8

Browse files
committed
Add a pipeline to collect Sigma rules
Signed-off-by: ziad hany <ziadhany2016@gmail.com>
1 parent ab99939 commit 749b9e8

File tree

8 files changed

+406
-0
lines changed

8 files changed

+406
-0
lines changed

vulnerabilities/improvers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
enhance_with_metasploit as enhance_with_metasploit_v2,
3131
)
3232
from vulnerabilities.pipelines.v2_improvers import flag_ghost_packages as flag_ghost_packages_v2
33+
from vulnerabilities.pipelines.v2_improvers import sigma_rules
3334
from vulnerabilities.pipelines.v2_improvers import unfurl_version_range as unfurl_version_range_v2
3435
from vulnerabilities.utils import create_registry
3536

@@ -70,5 +71,6 @@
7071
compute_advisory_todo_v2.ComputeToDo,
7172
unfurl_version_range_v2.UnfurlVersionRangePipeline,
7273
compute_advisory_todo.ComputeToDo,
74+
sigma_rules.SigmaRulesImproverPipeline,
7375
]
7476
)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Generated by Django 4.2.25 on 2025-11-24 19:30
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("vulnerabilities", "0103_codecommit_impactedpackage_affecting_commits_and_more"),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name="AdvisoryDetectionRule",
16+
fields=[
17+
(
18+
"id",
19+
models.AutoField(
20+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
21+
),
22+
),
23+
(
24+
"rule_text",
25+
models.TextField(
26+
help_text="Full text of the detection rule, script, or signature."
27+
),
28+
),
29+
(
30+
"rule_type",
31+
models.CharField(
32+
blank=True,
33+
choices=[
34+
("yara", "YARA"),
35+
("sigma", "Sigma Detection Rule"),
36+
("clamav", "ClamAV Signature"),
37+
],
38+
max_length=100,
39+
),
40+
),
41+
(
42+
"source_url",
43+
models.URLField(
44+
blank=True,
45+
help_text="URL or reference to the source of the rule (vendor feed, GitHub repo, etc.).",
46+
null=True,
47+
),
48+
),
49+
(
50+
"advisory",
51+
models.ForeignKey(
52+
on_delete=django.db.models.deletion.CASCADE,
53+
related_name="detection_rules",
54+
to="vulnerabilities.advisoryv2",
55+
),
56+
),
57+
],
58+
),
59+
]

vulnerabilities/models.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3414,3 +3414,31 @@ class CodeCommit(models.Model):
34143414

34153415
class Meta:
34163416
unique_together = ("commit_hash", "vcs_url")
3417+
3418+
3419+
class AdvisoryDetectionRule(models.Model):
3420+
"""
3421+
A detection rule (YARA, Sigma, ClamAV) linked to an advisory.
3422+
"""
3423+
3424+
RULE_TYPES = [
3425+
("yara", "YARA"),
3426+
("sigma", "Sigma Detection Rule"),
3427+
("clamav", "ClamAV Signature"),
3428+
]
3429+
3430+
advisory = models.ForeignKey(
3431+
AdvisoryV2,
3432+
related_name="detection_rules",
3433+
on_delete=models.CASCADE,
3434+
)
3435+
3436+
rule_text = models.TextField(help_text="Full text of the detection rule, script, or signature.")
3437+
3438+
rule_type = models.CharField(max_length=100, choices=RULE_TYPES, blank=True)
3439+
3440+
source_url = models.URLField(
3441+
null=True,
3442+
blank=True,
3443+
help_text="URL or reference to the source of the rule (vendor feed, GitHub repo, etc.).",
3444+
)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
10+
from pathlib import Path
11+
12+
import saneyaml
13+
from aboutcode.pipeline import LoopProgress
14+
from fetchcode.vcs import fetch_via_vcs
15+
from yaml import YAMLError
16+
17+
from vulnerabilities.models import AdvisoryAlias
18+
from vulnerabilities.models import AdvisoryDetectionRule
19+
from vulnerabilities.pipelines import VulnerableCodePipeline
20+
from vulnerabilities.utils import find_all_cve
21+
22+
23+
class SigmaRulesImproverPipeline(VulnerableCodePipeline):
24+
pipeline_id = "sigma_rules"
25+
repo_url = "git+https://github.com/SigmaHQ/sigma"
26+
license_url = "https://github.com/SigmaHQ/Detection-Rule-License"
27+
28+
@classmethod
29+
def steps(cls):
30+
return (
31+
cls.clone_repo,
32+
cls.collect_and_store_rules,
33+
cls.clean_downloads,
34+
)
35+
36+
def clone_repo(self):
37+
self.log(f"Cloning `{self.repo_url}`")
38+
self.vcs_response = fetch_via_vcs(self.repo_url)
39+
40+
def collect_and_store_rules(self):
41+
"""
42+
Collect Sigma YAML rules from the destination directory and store/update
43+
them as AdvisoryDetectionRule objects.
44+
"""
45+
46+
base_directory = Path(self.vcs_response.dest_dir)
47+
yaml_files = list(base_directory.rglob("**/*.yml"))
48+
rules_count = len(yaml_files)
49+
50+
self.log(f"Enhancing the vulnerability with {rules_count:,d} rule records")
51+
progress = LoopProgress(total_iterations=rules_count, logger=self.log)
52+
for file_path in progress.iter(yaml_files):
53+
cve_ids = find_all_cve(str(file_path))
54+
if not cve_ids or len(cve_ids) > 1:
55+
continue
56+
57+
cve_id = cve_ids[0]
58+
59+
with open(file_path, "r") as f:
60+
try:
61+
rule_data = saneyaml.load(f)
62+
except YAMLError as err:
63+
self.log(f"Invalid YAML in {file_path}: {err}. Skipping.")
64+
continue
65+
66+
advisories = set()
67+
try:
68+
if alias := AdvisoryAlias.objects.get(alias=cve_id):
69+
for adv in alias.advisories.all():
70+
advisories.add(adv)
71+
except AdvisoryAlias.DoesNotExist:
72+
self.log(f"Advisory {file_path.name} not found.")
73+
continue
74+
75+
rule_text = saneyaml.dump(rule_data)
76+
rule_url = f"https://raw.githubusercontent.com/SigmaHQ/sigma/refs/heads/master/{file_path.relative_to(base_directory)}"
77+
78+
for advisory in advisories:
79+
AdvisoryDetectionRule.objects.update_or_create(
80+
advisory=advisory,
81+
rule_type="sigma",
82+
defaults={
83+
"rule_text": rule_text,
84+
"source_url": rule_url,
85+
},
86+
)
87+
88+
self.log(f"Successfully added {rules_count:,d} rules advisory")
89+
90+
def clean_downloads(self):
91+
if self.vcs_response:
92+
self.log(f"Removing cloned repository")
93+
self.vcs_response.delete()
94+
95+
def on_failure(self):
96+
self.clean_downloads()
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
10+
import os
11+
from datetime import datetime
12+
from unittest import mock
13+
from unittest.mock import MagicMock
14+
15+
import pytest
16+
17+
from vulnerabilities.models import AdvisoryAlias
18+
from vulnerabilities.models import AdvisoryDetectionRule
19+
from vulnerabilities.models import AdvisoryV2
20+
from vulnerabilities.pipelines.v2_improvers.sigma_rules import SigmaRulesImproverPipeline
21+
22+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
23+
24+
TEST_REPO_DIR = os.path.join(BASE_DIR, "../../test_data/sigma")
25+
26+
27+
@pytest.mark.django_db
28+
@mock.patch("vulnerabilities.pipelines.v2_improvers.sigma_rules.fetch_via_vcs")
29+
def test_sigma_rules_db_improver(mock_fetch_via_vcs):
30+
mock_vcs = MagicMock()
31+
mock_vcs.dest_dir = TEST_REPO_DIR
32+
mock_vcs.delete = MagicMock()
33+
mock_fetch_via_vcs.return_value = mock_vcs
34+
35+
adv1 = AdvisoryV2.objects.create(
36+
advisory_id="VCIO-123-0001",
37+
datasource_id="ds",
38+
avid="ds/VCIO-123-0001",
39+
unique_content_id="sgsdg45",
40+
url="https://test.com",
41+
date_collected=datetime.now(),
42+
)
43+
adv2 = AdvisoryV2.objects.create(
44+
advisory_id="VCIO-123-1002",
45+
datasource_id="ds",
46+
avid="ds/VCIO-123-1002",
47+
unique_content_id="6hd4d6f",
48+
url="https://test.com",
49+
date_collected=datetime.now(),
50+
)
51+
adv3 = AdvisoryV2.objects.create(
52+
advisory_id="VCIO-123-1003",
53+
datasource_id="ds",
54+
avid="ds/VCIO-123-1003",
55+
unique_content_id="sd6h4sh",
56+
url="https://test.com",
57+
date_collected=datetime.now(),
58+
)
59+
60+
alias1 = AdvisoryAlias.objects.create(alias="CVE-2025-33053")
61+
alias2 = AdvisoryAlias.objects.create(alias="CVE-2025-10035")
62+
alias3 = AdvisoryAlias.objects.create(alias="CVE-2010-5278")
63+
adv1.aliases.add(alias1)
64+
adv2.aliases.add(alias2)
65+
adv3.aliases.add(alias3)
66+
67+
improver = SigmaRulesImproverPipeline()
68+
improver.execute()
69+
70+
assert len(AdvisoryDetectionRule.objects.all()) == 3
71+
sigma_rule = AdvisoryDetectionRule.objects.first()
72+
assert sigma_rule.rule_type == "sigma"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
title: CVE-2010-5278 Exploitation Attempt
2+
id: a4a899e8-fd7a-49dd-b5a8-7044def72d61
3+
status: test
4+
description: |
5+
MODx manager - Local File Inclusion:Directory traversal vulnerability in manager/controllers/default/resource/tvs.php in MODx Revolution 2.0.2-pl, and possibly earlier,
6+
when magic_quotes_gpc is disabled, allows remote attackers to read arbitrary files via a .. (dot dot) in the class_key parameter.
7+
references:
8+
- https://github.com/projectdiscovery/nuclei-templates
9+
author: Subhash Popuri (@pbssubhash)
10+
date: 2021-08-25
11+
modified: 2023-01-02
12+
tags:
13+
- attack.initial-access
14+
- attack.t1190
15+
- cve.2010-5278
16+
- detection.emerging-threats
17+
logsource:
18+
category: webserver
19+
detection:
20+
selection:
21+
cs-uri-query|contains: /manager/controllers/default/resource/tvs.php?class_key=../../../../../../../../../../windows/win.ini%00
22+
condition: selection
23+
falsepositives:
24+
- Scanning from Nuclei
25+
- Unknown
26+
level: critical
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
title: Potential Exploitation of GoAnywhere MFT Vulnerability
2+
id: 6c76b3d0-afe4-4870-9443-ffe6773c5fef
3+
status: experimental
4+
description: |
5+
Detects suspicious command execution by child processes of the GoAnywhere Managed File Transfer (MFT) application, which may indicate exploitation such as CVE-2025-10035.
6+
This behavior is indicative of post-exploitation activity related to CVE-2025-10035, as observed in campaigns by the threat actor Storm-1175.
7+
references:
8+
- https://www.microsoft.com/en-us/security/blog/2025/10/06/investigating-active-exploitation-of-cve-2025-10035-goanywhere-managed-file-transfer-vulnerability/
9+
author: MSFT (idea), Swachchhanda Shrawan Poudel (Nextron Systems)
10+
date: 2025-10-07
11+
tags:
12+
- attack.initial-access
13+
- attack.t1190
14+
- attack.execution
15+
- attack.t1059.001
16+
- attack.persistence
17+
- attack.t1133
18+
- detection.emerging-threats
19+
- cve.2025-10035
20+
logsource:
21+
category: process_creation
22+
product: windows
23+
detection:
24+
# Detects the GoAnywhere Tomcat parent process based on path and command line arguments
25+
selection_parent:
26+
ParentImage|contains: '\GoAnywhere\tomcat\'
27+
selection_powershell_img:
28+
Image|endswith:
29+
- '\powershell.exe'
30+
- '\powershell_ise.exe'
31+
- '\pwsh.exe'
32+
selection_powershell_cmd:
33+
- CommandLine|contains|all:
34+
- 'IEX'
35+
- 'enc'
36+
- 'Hidden'
37+
- 'bypass'
38+
- CommandLine|re:
39+
- 'net\s+user'
40+
- 'net\s+group'
41+
- 'query\s+session'
42+
- CommandLine|contains:
43+
- 'whoami'
44+
- 'systeminfo'
45+
- 'dsquery'
46+
- 'localgroup administrators'
47+
- 'nltest'
48+
- 'samaccountname='
49+
- 'adscredentials'
50+
- 'o365accountconfiguration'
51+
- '.DownloadString('
52+
- '.DownloadFile('
53+
- 'FromBase64String('
54+
- 'System.IO.Compression'
55+
- 'System.IO.MemoryStream'
56+
- 'curl'
57+
selection_child_cmd:
58+
Image|endswith: '\cmd.exe'
59+
CommandLine|contains:
60+
- 'powershell'
61+
- 'whoami'
62+
- 'net.exe'
63+
- 'net1.exe'
64+
- 'rundll32'
65+
- 'quser'
66+
- 'nltest'
67+
- 'curl'
68+
selection_child_others:
69+
CommandLine|contains:
70+
- 'bitsadmin'
71+
- 'certutil'
72+
- 'mshta'
73+
- 'cscript'
74+
- 'wscript'
75+
condition: selection_parent and (all of selection_powershell_* or 1 of selection_child_*)
76+
falsepositives:
77+
- Legitimate administrative scripts or built-in GoAnywhere functions could potentially trigger this rule. Tuning may be required based on normal activity in your environment.
78+
level: high

0 commit comments

Comments
 (0)