Skip to content

Commit daa12fd

Browse files
committed
implement n0s1 scanner #13564
1 parent 1df2832 commit daa12fd

6 files changed

Lines changed: 1482 additions & 0 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: "n0s1 Scanner"
3+
toc_hide: true
4+
---
5+
6+
### File Types
7+
Parser n0s1 expects a JSON file of scanner n0s1.
8+
9+
### Sample Scan Data
10+
Sample n0s1 scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/n0s1).
11+
12+
### Link To Tool
13+
See n0s1 on GitHub: https://github.com/spark1security/n0s1
14+
15+
### Default Deduplication Hashcode Fields
16+
By default, DefectDojo identifies duplicate Findings using these [hashcode fields](https://docs.defectdojo.com/en/working_with_findings/finding_deduplication/about_deduplication/):
17+
18+
- description

dojo/settings/settings.dist.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,7 @@ def saml2_attrib_map_format(din):
13951395
"Cycognito Scan": ["title", "severity"],
13961396
"OpenVAS Parser v2": ["title", "severity", "vuln_id_from_tool", "endpoints"],
13971397
"Snyk Issue API Scan": ["vuln_id_from_tool", "file_path"],
1398+
"n0s1 Scanner": ["description"],
13981399
}
13991400

14001401
# Override the hardcoded settings here via the env var

dojo/tools/n0s1/__init__.py

Whitespace-only changes.

dojo/tools/n0s1/parser.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
import json
3+
4+
from dojo.models import Finding
5+
6+
7+
class N0s1Parser:
8+
def get_scan_types(self):
9+
return ["n0s1 Scanner"]
10+
11+
def get_label_for_scan_types(self, scan_type):
12+
return scan_type
13+
14+
def get_description_for_scan_types(self, scan_type):
15+
return "JSON output from the n0s1 scanner."
16+
17+
def get_findings(self, filename, test):
18+
findings = []
19+
tree = filename.read()
20+
try:
21+
data = json.loads(str(tree, "utf-8"))
22+
except Exception:
23+
data = json.loads(tree)
24+
25+
# Load global regex rules
26+
regex_configs = {}
27+
if "regex_config" in data and "rules" in data["regex_config"]:
28+
for rule in data["regex_config"]["rules"]:
29+
regex_configs[rule["id"]] = rule
30+
31+
# Iterate over findings
32+
for finding_id, finding_data in data.get("findings", {}).items():
33+
details = finding_data.get("details", {})
34+
regex_ref = details.get("matched_regex_config", {})
35+
regex_id = regex_ref.get("id")
36+
37+
# Merge global config with local override
38+
regex_info = regex_configs.get(regex_id, {})
39+
merged_regex = {
40+
"id": regex_id,
41+
"description": regex_ref.get("description", regex_info.get("description", "N/A")),
42+
"regex": regex_ref.get("regex", regex_info.get("regex", "N/A")),
43+
"keywords": regex_info.get("keywords", []),
44+
"tags": regex_info.get("tags", []),
45+
}
46+
47+
title = merged_regex["id"] or "n0s1 Finding"
48+
description = f"**URL:** {finding_data.get('url', 'N/A')}\n"
49+
description += f"**Secret:** {finding_data.get('secret', 'N/A')}\n"
50+
description += f"**Platform:** {details.get('platform', 'N/A')}\n"
51+
description += f"**Ticket Field:** {details.get('ticket_field', 'N/A')}\n"
52+
description += f"**Regex ID:** {merged_regex['id']}\n"
53+
description += f"**Regex Description:** {merged_regex['description']}\n"
54+
description += f"**Regex Pattern:** {merged_regex['regex']}\n"
55+
if merged_regex["keywords"]:
56+
description += f"**Keywords:** {', '.join(merged_regex['keywords'])}\n"
57+
if merged_regex["tags"]:
58+
description += f"**Tags:** {', '.join(merged_regex['tags'])}\n"
59+
60+
find = Finding(
61+
title=title,
62+
test=test,
63+
description=description,
64+
severity="High", # You can adjust this based on your logic
65+
dynamic_finding=True,
66+
static_finding=False,
67+
unique_id_from_tool=finding_data.get("id", finding_id),
68+
)
69+
findings.append(find)
70+
71+
return findings

0 commit comments

Comments
 (0)