Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 42 additions & 42 deletions bbot/modules/baddns.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import asyncio
import logging

SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL")
CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED")


class baddns(BaseModule):
watched_events = ["DNS_NAME", "DNS_NAME_UNRESOLVED"]
Expand All @@ -15,14 +18,15 @@ class baddns(BaseModule):
"created_date": "2024-01-18",
"author": "@liquidsec",
}
options = {"custom_nameservers": [], "only_high_confidence": False, "enabled_submodules": []}
options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE", "enabled_submodules": []}
options_desc = {
"custom_nameservers": "Force BadDNS to use a list of custom nameservers",
"only_high_confidence": "Do not emit low-confidence or generic detections",
"min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)",
"min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)",
"enabled_submodules": "A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only",
}
module_threads = 8
deps_pip = ["baddns~=1.12.294"]
deps_pip = ["baddns~=2.0.0"]

def select_modules(self):
selected_submodules = []
Expand All @@ -36,12 +40,26 @@ def set_modules(self):
if self.enabled_submodules == []:
self.enabled_submodules = ["CNAME", "MX", "TXT"]

def _meets_threshold(self, severity, confidence):
sev_idx = SEVERITY_LEVELS.index(severity) if severity in SEVERITY_LEVELS else 0
conf_idx = CONFIDENCE_LEVELS.index(confidence) if confidence in CONFIDENCE_LEVELS else 0
return sev_idx >= self._min_sev_idx and conf_idx >= self._min_conf_idx

async def setup(self):
self.preset.core.logger.include_logger(logging.getLogger("baddns"))
self.custom_nameservers = self.config.get("custom_nameservers", []) or None
if self.custom_nameservers:
self.custom_nameservers = self.helpers.chain_lists(self.custom_nameservers)
self.only_high_confidence = self.config.get("only_high_confidence", False)
min_severity = self.config.get("min_severity", "LOW").upper()
min_confidence = self.config.get("min_confidence", "MODERATE").upper()
if min_severity not in SEVERITY_LEVELS:
self.warning(f"Invalid min_severity: {min_severity}, defaulting to LOW")
min_severity = "LOW"
if min_confidence not in CONFIDENCE_LEVELS:
self.warning(f"Invalid min_confidence: {min_confidence}, defaulting to MODERATE")
min_confidence = "MODERATE"
self._min_sev_idx = SEVERITY_LEVELS.index(min_severity)
self._min_conf_idx = CONFIDENCE_LEVELS.index(min_confidence)
self.signatures = load_signatures()
self.set_modules()
all_submodules_list = [m.name for m in get_all_modules()]
Expand Down Expand Up @@ -88,46 +106,28 @@ async def handle_event(self, event):
r_dict = r.to_dict()

confidence = r_dict["confidence"]
severity = r_dict["severity"]

if confidence in ["CONFIRMED", "PROBABLE"]:
data = {
"severity": "MEDIUM",
"name": f"BadDNS {r_dict['signature']}",
"confidence": "HIGH",
"description": f"{r_dict['description']}. Confidence: [{confidence}] Signature: [{r_dict['signature']}] Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]",
"host": str(event.host),
}
await self.emit_event(
data,
"FINDING",
event,
tags=[f"baddns-{module_instance.name.lower()}"],
context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {r_dict["description"]}',
if not self._meets_threshold(severity, confidence):
self.debug(
f"Skipping result below threshold (severity={severity}, confidence={confidence})"
)

elif confidence in ["UNLIKELY", "POSSIBLE"]:
if not self.only_high_confidence:
data = {
"name": f"BadDNS {r_dict['signature']}",
"description": f"{r_dict['description']} Confidence: [{confidence}] Signature: [{r_dict['signature']}] Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]",
"host": str(event.host),
"severity": "MEDIUM",
"confidence": "LOW",
}
await self.emit_event(
data,
"FINDING",
event,
tags=[f"baddns-{module_instance.name.lower()}"],
context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {r_dict["description"]}',
)
else:
self.debug(
f"Skipping low-confidence result due to only_high_confidence setting: {confidence}"
)

else:
self.warning(f"Got unrecognized confidence level: {confidence}")
continue

data = {
"severity": severity,
"name": f"BadDNS {r_dict['signature']}",
"confidence": confidence,
"description": f"{r_dict['description']}. Confidence: [{confidence}] Signature: [{r_dict['signature']}] Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]",
"host": str(event.host),
}
await self.emit_event(
data,
"FINDING",
event,
tags=[f"baddns-{module_instance.name.lower()}"],
context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {r_dict["description"]}',
)

found_domains = r_dict.get("found_domains", None)
if found_domains:
Expand Down
44 changes: 19 additions & 25 deletions bbot/modules/baddns_direct.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
from baddns.base import get_all_modules
from baddns.lib.loader import load_signatures
from .base import BaseModule
from .baddns import baddns as baddns_module

import logging


class baddns_direct(BaseModule):
class baddns_direct(baddns_module):
watched_events = ["URL", "STORAGE_BUCKET"]
produced_events = ["FINDING"]
flags = ["active", "safe", "subdomain-enum", "baddns", "cloud-enum"]
Expand All @@ -14,30 +10,19 @@ class baddns_direct(BaseModule):
"created_date": "2024-01-29",
"author": "@liquidsec",
}
options = {"custom_nameservers": []}
options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"}
options_desc = {
"custom_nameservers": "Force BadDNS to use a list of custom nameservers",
"min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)",
"min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)",
}
module_threads = 8
deps_pip = ["baddns~=1.12.294"]
deps_pip = ["baddns~=2.0.0"]

scope_distance_modifier = 1

async def setup(self):
self.preset.core.logger.include_logger(logging.getLogger("baddns"))
self.custom_nameservers = self.config.get("custom_nameservers", []) or None
if self.custom_nameservers:
self.custom_nameservers = self.helpers.chain_lists(self.custom_nameservers)
self.only_high_confidence = self.config.get("only_high_confidence", False)
self.signatures = load_signatures()
return True

def select_modules(self):
selected_modules = []
for m in get_all_modules():
if m.name in ["CNAME"]:
selected_modules.append(m)
return selected_modules
def set_modules(self):
self.enabled_submodules = ["CNAME"]

async def handle_event(self, event):
CNAME_direct_module = self.select_modules()[0]
Expand All @@ -56,12 +41,21 @@ async def handle_event(self, event):
for r in results:
r_dict = r.to_dict()

severity = r_dict["severity"]
confidence = r_dict["confidence"]

if not self._meets_threshold(severity, confidence):
self.debug(
f"Skipping result below threshold (severity={severity}, confidence={confidence})"
)
continue

data = {
"name": f"BadDNS {r_dict['signature']}",
"description": f"Possible [{r_dict['signature']}] via direct BadDNS analysis. Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]",
"host": str(event.host),
"severity": "HIGH",
"confidence": "MODERATE",
"severity": severity,
"confidence": confidence,
}

await self.emit_event(
Expand Down
7 changes: 4 additions & 3 deletions bbot/modules/baddns_zone.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ class baddns_zone(baddns_module):
"created_date": "2024-01-29",
"author": "@liquidsec",
}
options = {"custom_nameservers": [], "only_high_confidence": False}
options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"}
options_desc = {
"custom_nameservers": "Force BadDNS to use a list of custom nameservers",
"only_high_confidence": "Do not emit low-confidence or generic detections",
"min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)",
"min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)",
}
module_threads = 8
deps_pip = ["baddns~=1.12.294"]
deps_pip = ["baddns~=2.0.0"]

def set_modules(self):
self.enabled_submodules = ["NSEC", "zonetransfer"]
Expand Down
6 changes: 3 additions & 3 deletions bbot/modules/badsecrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class badsecrets(BaseModule):
options_desc = {
"custom_secrets": "Include custom secrets loaded from a local file",
}
deps_pip = ["badsecrets~=0.13.47"]
deps_pip = ["badsecrets~=1.0.0"]

async def setup(self):
self.custom_secrets = None
Expand Down Expand Up @@ -82,8 +82,8 @@ async def handle_event(self, event):
context=f'{{module}}\'s "{r["detecting_module"]}" module found known {r["description"]["product"]} secret ({{event.type}}): "{r["secret"]}"',
)
elif r["type"] == "IdentifyOnly":
# There is little value to presenting a non-vulnerable asp.net viewstate, as it is not crackable without a Matrioshka brain. Just emit a technology instead.
if r["detecting_module"] == "ASPNET_Viewstate":
# There is little value to presenting a non-vulnerable asp.net viewstate/resource, as it is not crackable without a Matrioshka brain. Just emit a technology instead.
if r["detecting_module"] in ("ASPNET_Viewstate", "ASPNET_Resource"):
technology = "microsoft asp.net"
await self.emit_event(
{"technology": technology, "url": event.data["url"], "host": str(event.host)},
Expand Down
Loading