Skip to content

Commit 07f2545

Browse files
committed
Add support for importing detection rules from https://github.com/aboutcode-data/detection-rules-collector
Add a test Signed-off-by: ziad hany <ziadhany2016@gmail.com>
1 parent 4ab8b2f commit 07f2545

10 files changed

Lines changed: 353 additions & 0 deletions

File tree

vulnerabilities/improvers/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
from vulnerabilities.pipelines import populate_vulnerability_summary_pipeline
2020
from vulnerabilities.pipelines import remove_duplicate_advisories
2121
from vulnerabilities.pipelines.v2_improvers import collect_ssvc_trees
22+
from vulnerabilities.pipelines.v2_improvers import compute_advisory_todo as compute_advisory_todo_v2
2223
from vulnerabilities.pipelines.v2_improvers import compute_package_risk as compute_package_risk_v2
2324
from vulnerabilities.pipelines.v2_improvers import (
2425
computer_package_version_rank as compute_version_rank_v2,
2526
)
27+
from vulnerabilities.pipelines.v2_improvers import detection_rules
2628
from vulnerabilities.pipelines.v2_improvers import enhance_with_exploitdb as exploitdb_v2
2729
from vulnerabilities.pipelines.v2_improvers import enhance_with_kev as enhance_with_kev_v2
2830
from vulnerabilities.pipelines.v2_improvers import (
@@ -72,5 +74,6 @@
7274
collect_ssvc_trees.CollectSSVCPipeline,
7375
relate_severities.RelateSeveritiesPipeline,
7476
group_advisories_for_packages.GroupAdvisoriesForPackages,
77+
detection_rules.DetectionRulesPipeline,
7578
]
7679
)

vulnerabilities/models.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3740,3 +3740,43 @@ class GroupedAdvisory(NamedTuple):
37403740
weighted_severity: Optional[float]
37413741
exploitability: Optional[float]
37423742
risk_score: Optional[float]
3743+
3744+
3745+
class DetectionRuleTypes(models.TextChoices):
3746+
"""Defines the supported formats for security detection rules."""
3747+
3748+
YARA = "yara", "Yara"
3749+
YARA_X = "yara-x", "Yara-X"
3750+
SIGMA = "sigma", "Sigma"
3751+
CLAMAV = "clamav", "ClamAV"
3752+
SURICATA = "suricata", "Suricata"
3753+
3754+
3755+
class DetectionRule(models.Model):
3756+
"""
3757+
A Detection Rule is code used to identify malicious activity or security threats.
3758+
"""
3759+
3760+
rule_type = models.CharField(
3761+
max_length=50,
3762+
choices=DetectionRuleTypes.choices,
3763+
help_text="The type of the detection rule content (e.g., YARA, Sigma).",
3764+
)
3765+
3766+
source_url = models.URLField(
3767+
max_length=1024, help_text="URL to the original source or reference for this rule."
3768+
)
3769+
3770+
rule_metadata = models.JSONField(
3771+
null=True,
3772+
blank=True,
3773+
help_text="Additional structured data such as tags, or author information.",
3774+
)
3775+
3776+
rule_text = models.TextField(help_text="The content of the detection signature.")
3777+
3778+
related_advisories = models.ManyToManyField(
3779+
AdvisoryV2,
3780+
related_name="detection_rules",
3781+
help_text="Advisories associated with this DetectionRule.",
3782+
)
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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 json
11+
from pathlib import Path
12+
13+
from fetchcode.vcs import fetch_via_vcs
14+
15+
from vulnerabilities.models import AdvisoryAlias
16+
from vulnerabilities.models import AdvisoryV2
17+
from vulnerabilities.models import DetectionRule
18+
from vulnerabilities.models import DetectionRuleTypes
19+
from vulnerabilities.pipelines import VulnerableCodePipeline
20+
21+
22+
class DetectionRulesPipeline(VulnerableCodePipeline):
23+
"""
24+
Pipeline to collect vulnerability scanner rules (Sigma, YARA, Suricata, ClamAV entries)
25+
"""
26+
27+
pipeline_id = "detection_rules"
28+
license_url = "https://github.com/ziadhany/detection-rules-collector/blob/master/LICENSE"
29+
precedence = 200
30+
31+
@classmethod
32+
def steps(cls):
33+
return (
34+
cls.clone,
35+
cls.collect_detection_rules,
36+
cls.clean_downloads,
37+
)
38+
39+
def clone(self):
40+
self.repo_url = "git+https://github.com/aboutcode-data/detection-rules-collector"
41+
self.log(f"Cloning `{self.repo_url}`")
42+
self.vcs_response = fetch_via_vcs(self.repo_url)
43+
44+
def advisories_count(self):
45+
root = Path(self.vcs_response.dest_dir)
46+
return sum(1 for _ in root.rglob("*.json"))
47+
48+
def collect_detection_rules(self):
49+
base_path = Path(self.vcs_response.dest_dir) / "data"
50+
rule_type_mapping = {
51+
DetectionRuleTypes.YARA: "yara/**/*.json",
52+
DetectionRuleTypes.SURICATA: "suricata/**/*.json",
53+
DetectionRuleTypes.SIGMA: "sigma/**/*.json",
54+
DetectionRuleTypes.CLAMAV: "clamav/**/*.json",
55+
}
56+
57+
for rule_type, glob_pattern in rule_type_mapping.items():
58+
for file_path in base_path.glob(glob_pattern):
59+
with open(file_path, "r") as f:
60+
try:
61+
json_data = json.load(f)
62+
except json.JSONDecodeError:
63+
self.log(f"Failed to parse JSON in {file_path}")
64+
continue
65+
66+
source_url = json_data.get("source_url")
67+
for rule in json_data.get("rules", []):
68+
advisories = set()
69+
for vulnerability_id in rule.get("vulnerabilities", []):
70+
try:
71+
if alias := AdvisoryAlias.objects.get(alias=vulnerability_id):
72+
for adv in alias.advisories.all():
73+
advisories.add(adv)
74+
else:
75+
advs = AdvisoryV2.objects.filter(
76+
advisory_id=vulnerability_id
77+
).latest_per_avid()
78+
for adv in advs:
79+
advisories.add(adv)
80+
except AdvisoryAlias.DoesNotExist:
81+
self.log(f"No advisory found for aliases {vulnerability_id}")
82+
83+
raw_text = rule.get("rule_text")
84+
detection_rule, _ = DetectionRule.objects.get_or_create(
85+
rule_text=raw_text,
86+
rule_type=rule_type,
87+
defaults={
88+
"source_url": source_url,
89+
},
90+
)
91+
if advisories:
92+
detection_rule.related_advisories.add(*advisories)
93+
94+
def clean_downloads(self):
95+
"""Cleanup any temporary repository data."""
96+
if self.vcs_response:
97+
self.log(f"Removing cloned repository")
98+
self.vcs_response.delete()
99+
100+
def on_failure(self):
101+
"""Ensure cleanup is always performed on failure."""
102+
self.clean_downloads()
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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.mock import Mock
13+
from unittest.mock import patch
14+
15+
import pytest
16+
17+
from vulnerabilities.models import AdvisoryAlias
18+
from vulnerabilities.models import AdvisoryV2
19+
from vulnerabilities.models import DetectionRule
20+
from vulnerabilities.pipelines.v2_improvers.detection_rules import DetectionRulesPipeline
21+
22+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
23+
TEST_DATA = os.path.join(BASE_DIR, "../../test_data", "detection_rules")
24+
25+
26+
@pytest.mark.django_db
27+
@patch("vulnerabilities.pipelines.v2_improvers.detection_rules.fetch_via_vcs")
28+
def test_detection_rules_improver(mock_fetch_via_vcs):
29+
mock_vcs_response = Mock()
30+
mock_vcs_response.dest_dir = TEST_DATA
31+
mock_fetch_via_vcs.return_value = mock_vcs_response
32+
33+
adv1 = AdvisoryV2.objects.create(
34+
advisory_id="VCIO-123-2002",
35+
datasource_id="ds",
36+
avid="ds/VCIO-123-2002",
37+
unique_content_id="i3giu",
38+
url="https://test.com",
39+
date_collected=datetime.now(),
40+
)
41+
alias = AdvisoryAlias.objects.create(alias="CVE-2007-4387")
42+
adv1.aliases.add(alias)
43+
44+
improver = DetectionRulesPipeline()
45+
improver.execute()
46+
assert DetectionRule.objects.count() > 0
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"source_url": "https://database.clamav.net/main.cvd?api-version=1",
3+
"source_filename": "main.hdb",
4+
"rules": [
5+
{
6+
"rule_metadata": {
7+
"name": "Eicar-Test-Signature",
8+
"line_num": 1
9+
},
10+
"rule_text": "44d88612fea8a8f36de82e1278abb02f:68:Eicar-Test-Signature",
11+
"vulnerabilities": []
12+
},
13+
{
14+
"rule_metadata": {
15+
"name": "Win.Trojan.Yat-2",
16+
"line_num": 3
17+
},
18+
"rule_text": "de3430cd6a3e24bfb9f78743a25f7c96:1098752:Win.Trojan.Yat-2",
19+
"vulnerabilities": []
20+
},
21+
{
22+
"rule_metadata": {
23+
"name": "Java.Exploit.CVE_2012_5076-1",
24+
"line_num": 10079
25+
},
26+
"rule_text": "a9b65b78619002a1b30ceee2d85fa770:205:Java.Exploit.CVE_2012_5076-1",
27+
"vulnerabilities": [
28+
"CVE-2012-5076"
29+
]
30+
}
31+
]
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"source_url": "https://database.clamav.net/main.cvd?api-version=1",
3+
"source_filename": "main.ldb",
4+
"rules": [
5+
{
6+
"rule_metadata": {
7+
"name": "Win.Exploit.CVE_2016_7185-1",
8+
"line_num": 1
9+
},
10+
"rule_text": "Win.Exploit.CVE_2016_7185-1;Engine:51-255,Target:1;(0&1&2&3);44616e6765726f757347657448616e646c65;5361666548616e646c655a65726f4f724d696e75734f6e654973496e76616c6964;52656c6561736548616e646c65;5c004400650076006900630065005c0044006600730043006c00690065006e007400",
11+
"vulnerabilities": [
12+
"CVE-2016-7185"
13+
]
14+
},
15+
{
16+
"rule_metadata": {
17+
"name": "Doc.Trojan.Agent-1383193",
18+
"line_num": 2
19+
},
20+
"rule_text": "Doc.Trojan.Agent-1383193;Engine:53-255,Target:2;0&1&2&3&4;57683370314d4c73576c69454b30626476376d707563704156724856585141694f30383755365a48556f;507a33593934674e796c784e724d5937706a3068;586c49766b65446349324259514d5169556b764d436165345144415452746d3842;434c70577561534d6f4c4845437a4172754d4d6466484b3334444e78;4256504271623368394c6e6c",
21+
"vulnerabilities": []
22+
},
23+
{
24+
"rule_metadata": {
25+
"name": "Doc.Trojan.Agent-1383194",
26+
"line_num": 3
27+
},
28+
"rule_text": "Doc.Trojan.Agent-1383194;Engine:53-255,Target:2;0&1>50;28373835362920417320427974652c20;3d2059656172284e6f77292027",
29+
"vulnerabilities": []
30+
}
31+
]
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"source_url": "https://database.clamav.net/main.cvd?api-version=1",
3+
"source_filename": "main.ndb",
4+
"rules": [
5+
{
6+
"rule_metadata": {
7+
"name": "Legacy.Trojan.Agent-1",
8+
"line_num": 1
9+
},
10+
"rule_text": "Legacy.Trojan.Agent-1:0:*:dd6d70241f674d8fc13e1eb3af731a7b5c43173c1cdd75722fa556c373b65c5275d513147b070077757064080386898ae75c6fb7f717b562ef636f6d6d613f2e0e202f6336c5eed52064f120228e2f6d27c101",
11+
"vulnerabilities": []
12+
},
13+
{
14+
"rule_metadata": {
15+
"name": "Win.Trojan.Hotkey-1",
16+
"line_num": 2
17+
},
18+
"rule_text": "Win.Trojan.Hotkey-1:0:*:c01640006a3cffb684000000ff159cef420089869800000089be940000008bc75f5ec20400565733ff8bf1397c240c741fff762089be8c000000ff1560ef42",
19+
"vulnerabilities": []
20+
},
21+
{
22+
"rule_metadata": {
23+
"name": "Win.Exploit.CVE_2001_0500-1",
24+
"line_num": 31344
25+
},
26+
"rule_text": "Win.Exploit.CVE_2001_0500-1:0:*:7961686f6f3a20607065726c202d6520277072696e7420225c783930227831313830302760245348454c4c434f44453d3230",
27+
"vulnerabilities": [
28+
"CVE-2001-0500"
29+
]
30+
}
31+
]
32+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"source_url": "https://github.com/SigmaHQ/sigma/blob/master/rules/web/webserver_generic/web_sql_injection_in_access_logs.yml",
3+
"rules": [
4+
{
5+
"rule_metadata": {
6+
"status": "test",
7+
"author": "Saw Win Naung, Nasreddine Bencherchali (Nextron Systems), Thurein Oo (Yoma Bank)",
8+
"date": "2020-02-22",
9+
"title": "SQL Injection Strings In URI",
10+
"id": "5513deaf-f49a-46c2-a6c8-3f111b5cb453"
11+
},
12+
"rule_text": "title: SQL Injection Strings In URI\nid: 5513deaf-f49a-46c2-a6c8-3f111b5cb453\nstatus: test\ndescription: Detects potential SQL injection attempts via GET requests in access logs.\nreferences:\n- https://www.acunetix.com/blog/articles/exploiting-sql-injection-example/\n- https://www.acunetix.com/blog/articles/using-logs-to-investigate-a-web-application-attack/\n- https://brightsec.com/blog/sql-injection-payloads/\n- https://github.com/payloadbox/sql-injection-payload-list\n- https://book.hacktricks.xyz/pentesting-web/sql-injection/mysql-injection\nauthor: Saw Win Naung, Nasreddine Bencherchali (Nextron Systems), Thurein Oo (Yoma\n Bank)\ndate: 2020-02-22\nmodified: 2023-09-04\ntags:\n- attack.initial-access\n- attack.t1190\nlogsource:\n category: webserver\ndetection:\n selection:\n cs-method: GET\n keywords:\n - '@@version'\n - '%271%27%3D%271'\n - '=select '\n - =select(\n - =select%20\n - concat_ws(\n - CONCAT(0x\n - from mysql.innodb_table_stats\n - from%20mysql.innodb_table_stats\n - group_concat(\n - information_schema.tables\n - json_arrayagg(\n - or 1=1#\n - or%201=1#\n - 'order by '\n - order%20by%20\n - 'select * '\n - select database()\n - select version()\n - select%20*%20\n - select%20database()\n - select%20version()\n - select%28sleep%2810%29\n - SELECTCHAR(\n - table_schema\n - UNION ALL SELECT\n - UNION SELECT\n - UNION%20ALL%20SELECT\n - UNION%20SELECT\n - '''1''=''1'\n filter_main_status:\n sc-status: 404\n condition: selection and keywords and not 1 of filter_main_*\nfalsepositives:\n- Java scripts and CSS Files\n- User searches in search boxes of the respective website\n- Internal vulnerability scanners can cause some serious FPs when used, if you experience\n a lot of FPs due to this think of adding more filters such as \"User Agent\" strings\n and more response codes\nlevel: high\n",
13+
"vulnerabilities": []
14+
}
15+
]
16+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"source_url": "https://github.com/OISF/suricata/blob/master/rules/dhcp-events.rules",
3+
"rules": [
4+
{
5+
"rule_metadata": {
6+
"name": "SURICATA DHCP malformed options",
7+
"version": 1,
8+
"id": 2227000,
9+
"enabled": true
10+
},
11+
"rule_text": "alert dhcp any any -> any any (msg:\"SURICATA DHCP malformed options\"; app-layer-event:dhcp.malformed_options; classtype:protocol-command-decode; sid:2227000; rev:1;)",
12+
"vulnerabilities": []
13+
},
14+
{
15+
"rule_metadata": {
16+
"name": "SURICATA DHCP truncated options",
17+
"version": 1,
18+
"id": 2227001,
19+
"enabled": true
20+
},
21+
"rule_text": "alert dhcp any any -> any any (msg:\"SURICATA DHCP truncated options\"; app-layer-event:dhcp.truncated_options; classtype:protocol-command-decode; sid:2227001; rev:1;)",
22+
"vulnerabilities": []
23+
}
24+
]
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"source_url": "https://github.com/elastic/protections-artifacts/blob/master/yara/rules/Linux_Backdoor_Bash.yar",
3+
"rules": [
4+
{
5+
"rule_metadata": {
6+
"name": "Linux_Backdoor_Bash_e427876d",
7+
"tags": [],
8+
"author": "Elastic Security",
9+
"id": "e427876d-c7c5-447a-ad6d-5cbc12d9dacf",
10+
"fingerprint": "6cc13bb2591d896affc58f4a22b3463a72f6c9d896594fe1714b825e064b0956",
11+
"creation_date": "2021-01-12",
12+
"last_modified": "2021-09-16",
13+
"threat_name": "Linux.Backdoor.Bash",
14+
"reference_sample": "07db41a4ddaac802b04df5e5bbae0881fead30cb8f6fa53a8a2e1edf14f2d36b",
15+
"severity": 100,
16+
"arch_context": "x86",
17+
"scan_context": "file, memory",
18+
"license": "Elastic License v2",
19+
"os": "linux"
20+
},
21+
"rule_text": "rule Linux_Backdoor_Bash_e427876d\n{\n\tmeta:\n\t\tauthor = \"Elastic Security\"\n\t\tid = \"e427876d-c7c5-447a-ad6d-5cbc12d9dacf\"\n\t\tfingerprint = \"6cc13bb2591d896affc58f4a22b3463a72f6c9d896594fe1714b825e064b0956\"\n\t\tcreation_date = \"2021-01-12\"\n\t\tlast_modified = \"2021-09-16\"\n\t\tthreat_name = \"Linux.Backdoor.Bash\"\n\t\treference_sample = \"07db41a4ddaac802b04df5e5bbae0881fead30cb8f6fa53a8a2e1edf14f2d36b\"\n\t\tseverity = 100\n\t\tarch_context = \"x86\"\n\t\tscan_context = \"file, memory\"\n\t\tlicense = \"Elastic License v2\"\n\t\tos = \"linux\"\n\n\tstrings:\n\t\t$a = { 67 65 44 6F 6B 4B 47 6C 6B 49 43 31 31 4B 54 6F 67 4C 32 56 }\n\n\tcondition:\n\t\tall of them\n}\n",
22+
"vulnerabilities": []
23+
}
24+
]
25+
}

0 commit comments

Comments
 (0)