bbot 2.3.0.5418rc0__py3-none-any.whl → 2.3.0.5438rc0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bbot might be problematic. Click here for more details.

bbot/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # version placeholder (replaced by poetry-dynamic-versioning)
2
- __version__ = "v2.3.0.5418rc"
2
+ __version__ = "v2.3.0.5438rc"
3
3
 
4
4
  from .scanner import Scanner, Preset
bbot/cli.py CHANGED
@@ -78,7 +78,7 @@ async def _main():
78
78
  return
79
79
 
80
80
  # if we're listing modules or their options
81
- if options.list_modules or options.list_module_options:
81
+ if options.list_modules or options.list_output_modules or options.list_module_options:
82
82
  # if no modules or flags are specified, enable everything
83
83
  if not (options.modules or options.output_modules or options.flags):
84
84
  for module, preloaded in preset.module_loader.preloaded().items():
@@ -96,7 +96,17 @@ async def _main():
96
96
  print("")
97
97
  print("### MODULES ###")
98
98
  print("")
99
- for row in preset.module_loader.modules_table(preset.modules).splitlines():
99
+ modules = sorted(set(preset.scan_modules + preset.internal_modules))
100
+ for row in preset.module_loader.modules_table(modules).splitlines():
101
+ print(row)
102
+ return
103
+
104
+ # --list-output-modules
105
+ if options.list_output_modules:
106
+ print("")
107
+ print("### OUTPUT MODULES ###")
108
+ print("")
109
+ for row in preset.module_loader.modules_table(preset.output_modules).splitlines():
100
110
  print(row)
101
111
  return
102
112
 
@@ -293,6 +293,7 @@ names = [
293
293
  "alyssa",
294
294
  "amanda",
295
295
  "amber",
296
+ "amir",
296
297
  "amy",
297
298
  "andrea",
298
299
  "andrew",
bbot/modules/base.py CHANGED
@@ -51,7 +51,7 @@ class BaseModule:
51
51
 
52
52
  target_only (bool): Accept only the initial target event(s). Default is False.
53
53
 
54
- in_scope_only (bool): Accept only explicitly in-scope events. Default is False.
54
+ in_scope_only (bool): Accept only explicitly in-scope events, regardless of the scan's search distance. Default is False.
55
55
 
56
56
  options (Dict): Customizable options for the module, e.g., {"api_key": ""}. Empty dict by default.
57
57
 
@@ -5,7 +5,11 @@ from bbot.modules.base import BaseInterceptModule
5
5
 
6
6
  class CloudCheck(BaseInterceptModule):
7
7
  watched_events = ["*"]
8
- meta = {"description": "Tag events by cloud provider, identify cloud resources like storage buckets"}
8
+ meta = {
9
+ "description": "Tag events by cloud provider, identify cloud resources like storage buckets",
10
+ "created_date": "2024-07-07",
11
+ "author": "@TheTechromancer",
12
+ }
9
13
  scope_distance_modifier = 1
10
14
  _priority = 3
11
15
 
@@ -9,6 +9,8 @@ from bbot.modules.base import BaseInterceptModule, BaseModule
9
9
 
10
10
  class DNSResolve(BaseInterceptModule):
11
11
  watched_events = ["*"]
12
+ produced_events = ["DNS_NAME", "IP_ADDRESS", "RAW_DNS_RECORD"]
13
+ meta = {"description": "Perform DNS resolution", "created_date": "2022-04-08", "author": "@TheTechromancer"}
12
14
  _priority = 1
13
15
  scope_distance_modifier = None
14
16
 
@@ -83,9 +85,14 @@ class DNSResolve(BaseInterceptModule):
83
85
  event_data_changed = await self.handle_wildcard_event(main_host_event)
84
86
  if event_data_changed:
85
87
  # since data has changed, we check again whether it's a duplicate
86
- if event.type == "DNS_NAME" and self.scan.ingress_module.is_incoming_duplicate(event, add=True):
88
+ if event.type == "DNS_NAME" and self.scan.ingress_module.is_incoming_duplicate(
89
+ event, add=True
90
+ ):
87
91
  if not event._graph_important:
88
- return False, "it's a DNS wildcard, and its module already emitted a similar wildcard event"
92
+ return (
93
+ False,
94
+ "it's a DNS wildcard, and its module already emitted a similar wildcard event",
95
+ )
89
96
  else:
90
97
  self.debug(
91
98
  f"Event {event} was already emitted by its module, but it's graph-important so it gets a pass"
@@ -656,8 +656,10 @@ class excavate(BaseInternalModule, BaseInterceptModule):
656
656
  continue
657
657
  if parsed_url.scheme in ["http", "https"]:
658
658
  continue
659
+
659
660
  def abort_if(e):
660
661
  return e.scope_distance > 0
662
+
661
663
  finding_data = {"host": str(host), "description": f"Non-HTTP URI: {parsed_url.geturl()}"}
662
664
  await self.report(finding_data, event, yara_rule_settings, discovery_context, abort_if=abort_if)
663
665
  protocol_data = {"protocol": parsed_url.scheme, "host": str(host)}
@@ -104,7 +104,7 @@ class speculate(BaseInternalModule):
104
104
  # don't act on unresolved DNS_NAMEs
105
105
  usable_dns = False
106
106
  if event.type == "DNS_NAME":
107
- if self.dns_disable or ("a-record" in event.tags or "aaaa-record" in event.tags):
107
+ if self.dns_disable or event.resolved_hosts:
108
108
  usable_dns = True
109
109
 
110
110
  if event.type == "IP_ADDRESS" or usable_dns:
@@ -3,7 +3,7 @@ from bbot.modules.templates.sql import SQLTemplate
3
3
 
4
4
  class MySQL(SQLTemplate):
5
5
  watched_events = ["*"]
6
- meta = {"description": "Output scan data to a MySQL database"}
6
+ meta = {"description": "Output scan data to a MySQL database", "created_date": "2024-11-13", "author": "@TheTechromancer"}
7
7
  options = {
8
8
  "username": "root",
9
9
  "password": "bbotislife",
@@ -0,0 +1,171 @@
1
+ import sys
2
+ from xml.dom import minidom
3
+ from datetime import datetime
4
+ from xml.etree.ElementTree import Element, SubElement, tostring
5
+
6
+ from bbot import __version__
7
+ from bbot.modules.output.base import BaseOutputModule
8
+
9
+
10
+ class NmapHost:
11
+ __slots__ = ["hostnames", "open_ports"]
12
+
13
+ def __init__(self):
14
+ self.hostnames = set()
15
+ # a dict of {port: {protocol: banner}}
16
+ self.open_ports = dict()
17
+
18
+
19
+ class Nmap_XML(BaseOutputModule):
20
+ watched_events = ["OPEN_TCP_PORT", "DNS_NAME", "IP_ADDRESS", "PROTOCOL", "HTTP_RESPONSE"]
21
+ meta = {"description": "Output to Nmap XML", "created_date": "2024-11-16", "author": "@TheTechromancer"}
22
+ output_filename = "output.nmap.xml"
23
+ in_scope_only = True
24
+
25
+ async def setup(self):
26
+ self.hosts = {}
27
+ self._prep_output_dir(self.output_filename)
28
+ return True
29
+
30
+ async def handle_event(self, event):
31
+ event_host = event.host
32
+
33
+ # we always record by IP
34
+ ips = []
35
+ for ip in event.resolved_hosts:
36
+ try:
37
+ ips.append(self.helpers.make_ip_type(ip))
38
+ except ValueError:
39
+ continue
40
+ if not ips and self.helpers.is_ip(event_host):
41
+ ips = [event_host]
42
+
43
+ for ip in ips:
44
+ try:
45
+ nmap_host = self.hosts[ip]
46
+ except KeyError:
47
+ nmap_host = NmapHost()
48
+ self.hosts[ip] = nmap_host
49
+
50
+ event_port = getattr(event, "port", None)
51
+ if event.type == "OPEN_TCP_PORT":
52
+ if event_port not in nmap_host.open_ports:
53
+ nmap_host.open_ports[event.port] = {}
54
+ elif event.type in ("PROTOCOL", "HTTP_RESPONSE"):
55
+ if event_port is not None:
56
+ try:
57
+ existing_services = nmap_host.open_ports[event.port]
58
+ except KeyError:
59
+ existing_services = {}
60
+ nmap_host.open_ports[event.port] = existing_services
61
+ if event.type == "PROTOCOL":
62
+ protocol = event.data["protocol"].lower()
63
+ banner = event.data.get("banner", None)
64
+ elif event.type == "HTTP_RESPONSE":
65
+ protocol = event.parsed_url.scheme.lower()
66
+ banner = event.http_title
67
+ if protocol not in existing_services:
68
+ existing_services[protocol] = banner
69
+
70
+ if self.helpers.is_ip(event_host):
71
+ if str(event.module) == "PTR":
72
+ nmap_host.hostnames.add(event.parent.data)
73
+ else:
74
+ nmap_host.hostnames.add(event_host)
75
+
76
+ async def report(self):
77
+ scan_start_time = str(int(self.scan.start_time.timestamp()))
78
+ scan_start_time_str = self.scan.start_time.strftime("%a %b %d %H:%M:%S %Y")
79
+ scan_end_time = datetime.now()
80
+ scan_end_time_str = scan_end_time.strftime("%a %b %d %H:%M:%S %Y")
81
+ scan_end_time_timestamp = str(scan_end_time.timestamp())
82
+ scan_duration = scan_end_time - self.scan.start_time
83
+ num_hosts_up = len(self.hosts)
84
+
85
+ # Create the root element
86
+ nmaprun = Element(
87
+ "nmaprun",
88
+ {
89
+ "scanner": "bbot",
90
+ "args": " ".join(sys.argv),
91
+ "start": scan_start_time,
92
+ "startstr": scan_start_time_str,
93
+ "version": str(__version__),
94
+ "xmloutputversion": "1.05",
95
+ },
96
+ )
97
+
98
+ ports_scanned = []
99
+ speculate_module = self.scan.modules.get("speculate", None)
100
+ if speculate_module is not None:
101
+ ports_scanned = speculate_module.ports
102
+ portscan_module = self.scan.modules.get("portscan", None)
103
+ if portscan_module is not None:
104
+ ports_scanned = self.helpers.parse_port_string(str(portscan_module.ports))
105
+ num_ports_scanned = len(sorted(ports_scanned))
106
+ ports_scanned = ",".join(str(x) for x in sorted(ports_scanned))
107
+
108
+ # Add scaninfo
109
+ SubElement(
110
+ nmaprun,
111
+ "scaninfo",
112
+ {"type": "syn", "protocol": "tcp", "numservices": str(num_ports_scanned), "services": ports_scanned},
113
+ )
114
+
115
+ # Add host information
116
+ for ip, nmap_host in self.hosts.items():
117
+ hostnames = sorted(nmap_host.hostnames)
118
+ ports = sorted(nmap_host.open_ports)
119
+
120
+ host_elem = SubElement(nmaprun, "host")
121
+ SubElement(host_elem, "status", {"state": "up", "reason": "user-set", "reason_ttl": "0"})
122
+ SubElement(host_elem, "address", {"addr": str(ip), "addrtype": f"ipv{ip.version}"})
123
+
124
+ if hostnames:
125
+ hostnames_elem = SubElement(host_elem, "hostnames")
126
+ for hostname in hostnames:
127
+ SubElement(hostnames_elem, "hostname", {"name": hostname, "type": "user"})
128
+
129
+ ports = SubElement(host_elem, "ports")
130
+ for port, protocols in nmap_host.open_ports.items():
131
+ port_elem = SubElement(ports, "port", {"protocol": "tcp", "portid": str(port)})
132
+ SubElement(port_elem, "state", {"state": "open", "reason": "syn-ack", "reason_ttl": "0"})
133
+ # <port protocol="tcp" portid="443"><state state="open" reason="syn-ack" reason_ttl="53"/><service name="http" product="AkamaiGHost" extrainfo="Akamai&apos;s HTTP Acceleration/Mirror service" tunnel="ssl" method="probed" conf="10"/></port>
134
+ for protocol, banner in protocols.items():
135
+ attrs = {"name": protocol, "method": "probed", "conf": "10"}
136
+ if banner is not None:
137
+ attrs["product"] = banner
138
+ attrs["extrainfo"] = banner
139
+ SubElement(port_elem, "service", attrs)
140
+
141
+ # Add runstats
142
+ runstats = SubElement(nmaprun, "runstats")
143
+ SubElement(
144
+ runstats,
145
+ "finished",
146
+ {
147
+ "time": scan_end_time_timestamp,
148
+ "timestr": scan_end_time_str,
149
+ "summary": f"BBOT done at {scan_end_time_str}; {num_hosts_up} scanned in {scan_duration} seconds",
150
+ "elapsed": str(scan_duration.total_seconds()),
151
+ "exit": "success",
152
+ },
153
+ )
154
+ SubElement(runstats, "hosts", {"up": str(num_hosts_up), "down": "0", "total": str(num_hosts_up)})
155
+
156
+ # make backup of the file
157
+ self.helpers.backup_file(self.output_file)
158
+
159
+ # Pretty-format the XML
160
+ rough_string = tostring(nmaprun, encoding="utf-8")
161
+ reparsed = minidom.parseString(rough_string)
162
+
163
+ # Create a new document with the doctype
164
+ doctype = minidom.DocumentType("nmaprun")
165
+ reparsed.insertBefore(doctype, reparsed.documentElement)
166
+
167
+ pretty_xml = reparsed.toprettyxml(indent=" ")
168
+
169
+ with open(self.output_file, "w") as f:
170
+ f.write(pretty_xml)
171
+ self.info(f"Saved Nmap XML output to {self.output_file}")
@@ -3,7 +3,11 @@ from bbot.modules.templates.sql import SQLTemplate
3
3
 
4
4
  class Postgres(SQLTemplate):
5
5
  watched_events = ["*"]
6
- meta = {"description": "Output scan data to a SQLite database"}
6
+ meta = {
7
+ "description": "Output scan data to a SQLite database",
8
+ "created_date": "2024-11-08",
9
+ "author": "@TheTechromancer",
10
+ }
7
11
  options = {
8
12
  "username": "postgres",
9
13
  "password": "bbotislife",
@@ -5,7 +5,11 @@ from bbot.modules.templates.sql import SQLTemplate
5
5
 
6
6
  class SQLite(SQLTemplate):
7
7
  watched_events = ["*"]
8
- meta = {"description": "Output scan data to a SQLite database"}
8
+ meta = {
9
+ "description": "Output scan data to a SQLite database",
10
+ "created_date": "2024-11-07",
11
+ "author": "@TheTechromancer",
12
+ }
9
13
  options = {
10
14
  "database": "",
11
15
  }
@@ -6,7 +6,7 @@ from bbot.modules.output.base import BaseOutputModule
6
6
 
7
7
  class Stdout(BaseOutputModule):
8
8
  watched_events = ["*"]
9
- meta = {"description": "Output to text"}
9
+ meta = {"description": "Output to text", "created_date": "2024-04-03", "author": "@TheTechromancer"}
10
10
  options = {"format": "text", "event_types": [], "event_fields": [], "in_scope_only": False, "accept_dupes": True}
11
11
  options_desc = {
12
12
  "format": "Which text format to display, choices: text,json",
@@ -5,7 +5,7 @@ from bbot.modules.output.base import BaseOutputModule
5
5
 
6
6
  class TXT(BaseOutputModule):
7
7
  watched_events = ["*"]
8
- meta = {"description": "Output to text"}
8
+ meta = {"description": "Output to text", "created_date": "2024-04-03", "author": "@TheTechromancer"}
9
9
  options = {"output_file": ""}
10
10
  options_desc = {"output_file": "Output to file"}
11
11
 
@@ -52,6 +52,11 @@ class BBOTArgs:
52
52
  "",
53
53
  "bbot -l",
54
54
  ),
55
+ (
56
+ "List output modules",
57
+ "",
58
+ "bbot -lo",
59
+ ),
55
60
  (
56
61
  "List presets",
57
62
  "",
@@ -290,12 +295,6 @@ class BBOTArgs:
290
295
  )
291
296
 
292
297
  output = p.add_argument_group(title="Output")
293
- output.add_argument(
294
- "-o",
295
- "--output-dir",
296
- help="Directory to output scan results",
297
- metavar="DIR",
298
- )
299
298
  output.add_argument(
300
299
  "-om",
301
300
  "--output-modules",
@@ -304,6 +303,13 @@ class BBOTArgs:
304
303
  help=f'Output module(s). Choices: {",".join(sorted(self.preset.module_loader.output_module_choices))}',
305
304
  metavar="MODULE",
306
305
  )
306
+ output.add_argument("-lo", "--list-output-modules", action="store_true", help="List available output modules")
307
+ output.add_argument(
308
+ "-o",
309
+ "--output-dir",
310
+ help="Directory to output scan results",
311
+ metavar="DIR",
312
+ )
307
313
  output.add_argument("--json", "-j", action="store_true", help="Output scan data in JSON format")
308
314
  output.add_argument("--brief", "-br", action="store_true", help="Output only the data itself")
309
315
  output.add_argument("--event-types", nargs="+", default=[], help="Choose which event types to display")
bbot/scanner/target.py CHANGED
@@ -192,7 +192,6 @@ class ScanBlacklist(ACLTarget):
192
192
  @special_target_type(r"^(?:RE|REGEX):(.*)")
193
193
  def handle_regex(self, match):
194
194
  pattern = match.group(1)
195
- log.info(f"Blacklisting by custom regex: {pattern}")
196
195
  blacklist_regex = re.compile(pattern, re.IGNORECASE)
197
196
  self.blacklist_regexes.add(blacklist_regex)
198
197
  return []
@@ -225,6 +224,12 @@ class ScanBlacklist(ACLTarget):
225
224
  hosts = [str(h).encode() for h in self.sorted_hosts]
226
225
  return hosts + regex_patterns
227
226
 
227
+ def __len__(self):
228
+ return super().__len__() + len(self.blacklist_regexes)
229
+
230
+ def __bool__(self):
231
+ return bool(len(self))
232
+
228
233
 
229
234
  class BBOTTarget:
230
235
  """
@@ -150,11 +150,23 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config):
150
150
  out, err = capsys.readouterr()
151
151
  # internal modules
152
152
  assert "| excavate " in out
153
- # output modules
154
- assert "| csv " in out
153
+ # no output modules
154
+ assert not "| csv " in out
155
155
  # scan modules
156
156
  assert "| wayback " in out
157
157
 
158
+ # list output modules
159
+ monkeypatch.setattr("sys.argv", ["bbot", "--list-output-modules"])
160
+ result = await cli._main()
161
+ assert result == None
162
+ out, err = capsys.readouterr()
163
+ # no internal modules
164
+ assert not "| excavate " in out
165
+ # output modules
166
+ assert "| csv " in out
167
+ # no scan modules
168
+ assert not "| wayback " in out
169
+
158
170
  # output dir and scan name
159
171
  output_dir = bbot_test_dir / "bbot_cli_args_output"
160
172
  scan_name = "bbot_cli_args_scan_name"
@@ -156,17 +156,15 @@ async def test_modules_basic_checks(events, httpx_mock):
156
156
  assert not (
157
157
  "web-basic" in flags and "web-thorough" in flags
158
158
  ), f'module "{module_name}" should have either "web-basic" or "web-thorough" flags, not both'
159
- meta = preloaded.get("meta", {})
160
- # make sure every module has a description
161
- assert meta.get("description", ""), f"{module_name} must have a description"
162
- # make sure every module has an author
163
- assert meta.get("author", ""), f"{module_name} must have an author"
164
- # make sure every module has a created date
165
- created_date = meta.get("created_date", "")
166
- assert created_date, f"{module_name} must have a created date"
167
- assert created_date_regex.match(
168
- created_date
169
- ), f"{module_name}'s created_date must match the format YYYY-MM-DD"
159
+ meta = preloaded.get("meta", {})
160
+ # make sure every module has a description
161
+ assert meta.get("description", ""), f"{module_name} must have a description"
162
+ # make sure every module has an author
163
+ assert meta.get("author", ""), f"{module_name} must have an author"
164
+ # make sure every module has a created date
165
+ created_date = meta.get("created_date", "")
166
+ assert created_date, f"{module_name} must have a created date"
167
+ assert created_date_regex.match(created_date), f"{module_name}'s created_date must match the format YYYY-MM-DD"
170
168
 
171
169
  # attribute checks
172
170
  watched_events = preloaded.get("watched_events")
@@ -395,6 +395,7 @@ async def test_blacklist_regex(bbot_scanner, bbot_httpserver):
395
395
  config={"excavate": True},
396
396
  debug=True,
397
397
  )
398
+ assert len(scan.target.blacklist) == 2
398
399
  assert scan.target.blacklist.blacklist_regexes
399
400
  assert {r.pattern for r in scan.target.blacklist.blacklist_regexes} == {
400
401
  r"evil[0-9]{3}",
@@ -0,0 +1,85 @@
1
+ import xml.etree.ElementTree as ET
2
+
3
+ from bbot.modules.base import BaseModule
4
+ from .base import ModuleTestBase
5
+
6
+
7
+ class TestNmap_XML(ModuleTestBase):
8
+ modules_overrides = ["nmap_xml", "speculate"]
9
+ targets = ["blacklanternsecurity.com", "127.0.0.3"]
10
+ config_overrides = {"dns": {"minimal": False}}
11
+
12
+ class DummyModule(BaseModule):
13
+ watched_events = ["OPEN_TCP_PORT"]
14
+ _name = "dummy_module"
15
+
16
+ async def handle_event(self, event):
17
+ if event.port == 80:
18
+ await self.emit_event(
19
+ {"host": str(event.host), "port": event.port, "protocol": "http", "banner": "Apache"},
20
+ "PROTOCOL",
21
+ parent=event,
22
+ )
23
+ elif event.port == 443:
24
+ await self.emit_event(
25
+ {"host": str(event.host), "port": event.port, "protocol": "https"}, "PROTOCOL", parent=event
26
+ )
27
+
28
+ async def setup_before_prep(self, module_test):
29
+ self.dummy_module = self.DummyModule(module_test.scan)
30
+ module_test.scan.modules["dummy_module"] = self.dummy_module
31
+ await module_test.mock_dns(
32
+ {
33
+ "blacklanternsecurity.com": {"A": ["127.0.0.1", "127.0.0.2"]},
34
+ "3.0.0.127.in-addr.arpa": {"PTR": ["www.blacklanternsecurity.com"]},
35
+ "www.blacklanternsecurity.com": {"A": ["127.0.0.1"]},
36
+ }
37
+ )
38
+
39
+ def check(self, module_test, events):
40
+ nmap_xml_file = module_test.scan.modules["nmap_xml"].output_file
41
+ nmap_xml = open(nmap_xml_file).read()
42
+
43
+ # Parse the XML
44
+ root = ET.fromstring(nmap_xml)
45
+
46
+ # Expected IP addresses
47
+ expected_ips = {"127.0.0.1", "127.0.0.2", "127.0.0.3"}
48
+ found_ips = set()
49
+
50
+ # Iterate over each host in the XML
51
+ for host in root.findall("host"):
52
+ # Get the IP address
53
+ address = host.find("address").get("addr")
54
+ found_ips.add(address)
55
+
56
+ # Get hostnames if available
57
+ hostnames = sorted([hostname.get("name") for hostname in host.findall(".//hostname")])
58
+
59
+ # Get open ports and services
60
+ ports = []
61
+ for port in host.findall(".//port"):
62
+ port_id = port.get("portid")
63
+ state = port.find("state").get("state")
64
+ if state == "open":
65
+ service_name = port.find("service").get("name")
66
+ service_product = port.find("service").get("product", "")
67
+ service_extrainfo = port.find("service").get("extrainfo", "")
68
+ ports.append((port_id, service_name, service_product, service_extrainfo))
69
+
70
+ # Sort ports for consistency
71
+ ports.sort()
72
+
73
+ # Assertions
74
+ if address == "127.0.0.1":
75
+ assert hostnames == ["blacklanternsecurity.com", "www.blacklanternsecurity.com"]
76
+ assert ports == sorted([("80", "http", "Apache", "Apache"), ("443", "https", "", "")])
77
+ elif address == "127.0.0.2":
78
+ assert hostnames == sorted(["blacklanternsecurity.com"])
79
+ assert ports == sorted([("80", "http", "Apache", "Apache"), ("443", "https", "", "")])
80
+ elif address == "127.0.0.3":
81
+ assert hostnames == [] # No hostnames for this IP
82
+ assert ports == sorted([("80", "http", "Apache", "Apache"), ("443", "https", "", "")])
83
+
84
+ # Assert that all expected IPs were found
85
+ assert found_ips == expected_ips
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bbot
3
- Version: 2.3.0.5418rc0
3
+ Version: 2.3.0.5438rc0
4
4
  Summary: OSINT automation for hackers.
5
5
  Home-page: https://github.com/blacklanternsecurity/bbot
6
6
  License: GPL-3.0
@@ -1,5 +1,5 @@
1
- bbot/__init__.py,sha256=qHf85UfjVTNc5OVxvCj-BhW-gd0vPhbyJtHwYfPTzw4,130
2
- bbot/cli.py,sha256=xPTXsZr8FGmI3N6e3gjo9i9E2u-Ih2Sr4MQU6RTxnj8,10434
1
+ bbot/__init__.py,sha256=PSBAzvTIlXQ6VGkKm7voHEz1M3On9Kmudq3sMhhIMQM,130
2
+ bbot/cli.py,sha256=Qlgqabm8N6r6uO1RuwGaM7-VXDSP_NH-YUnDUTsDYPM,10877
3
3
  bbot/core/__init__.py,sha256=l255GJE_DvUnWvrRb0J5lG-iMztJ8zVvoweDOfegGtI,46
4
4
  bbot/core/config/__init__.py,sha256=zYNw2Me6tsEr8hOOkLb4BQ97GB7Kis2k--G81S8vofU,342
5
5
  bbot/core/config/files.py,sha256=zANvrTRLJQIOWSNkxd9MpWmf9cQFr0gRZLUxeIbTwQc,1412
@@ -30,7 +30,7 @@ bbot/core/helpers/helper.py,sha256=eD9yJUhrFUmmoXm4pyi31dulJ5W2eyS-YLGXmx7AyDQ,8
30
30
  bbot/core/helpers/interactsh.py,sha256=VBYYH6-rWBofRsgemndK6iZNmyifOps8vgQOw2mac4k,12624
31
31
  bbot/core/helpers/libmagic.py,sha256=QMHyxjgDLb2jyjBvK1MQ-xt6WkGXhKcHu9ZP1li-sik,3460
32
32
  bbot/core/helpers/misc.py,sha256=156tWmNGZ0I1X537hQ8cAlShVq8D2dQVGz3DxaLh5d0,87734
33
- bbot/core/helpers/names_generator.py,sha256=Sj_Q-7KQyElEpalzlUadSwaniESqrIVVEle9ycPIiho,10322
33
+ bbot/core/helpers/names_generator.py,sha256=x6nZfEPKMwv3qR_RI4U6TBNbo6PgCF4fqbldtwilvpw,10334
34
34
  bbot/core/helpers/ntlm.py,sha256=P2Xj4-GPos2iAzw4dfk0FJp6oGyycGhu2x6sLDVjYjs,2573
35
35
  bbot/core/helpers/process.py,sha256=00uRpLMFi3Pt3uT8qXwAIhsXdoa7h-ifoXh0sGYgwqs,1702
36
36
  bbot/core/helpers/ratelimiter.py,sha256=K8qFIyJPJtfdb9kSW6_lL6ahWqxR2uWyCBkDlg6uJgo,1990
@@ -61,7 +61,7 @@ bbot/modules/baddns.py,sha256=SP-o0M2dq5QIkaQZUKl9YZiOXdZasty-fHPxTJJAeR0,6378
61
61
  bbot/modules/baddns_direct.py,sha256=pe_seO74XI4b6w4Q_IBDNvtBjmD-7it5ts0Z-FB0L6k,3818
62
62
  bbot/modules/baddns_zone.py,sha256=IcewDBtA_-64NCNFojEFd9jt2YBek6ltB2mmqdDH6LE,1034
63
63
  bbot/modules/badsecrets.py,sha256=JSukBYdD3yuvVy84DkyX48428R_LgQ7P39tjTRAD_Mo,5107
64
- bbot/modules/base.py,sha256=zNjF1-174Svg8SW07J7QahLVkVyCyEBxi7k2YF4FIUk,71101
64
+ bbot/modules/base.py,sha256=Ala_jLu3I2iEadn_NNiOb4RnFdJPwlrtywASDvd-P6c,71143
65
65
  bbot/modules/bevigil.py,sha256=0VLIxmeXRUI2-EoR6IzuHJMcX8KCHNNta-WYa3gVlDg,2862
66
66
  bbot/modules/binaryedge.py,sha256=5F9LnZwRM_rZnzTv29hLJLI2GEQdzOwSpahPFC1kJC0,1397
67
67
  bbot/modules/bucket_amazon.py,sha256=mwjYeEAcdfOpjbOa1sD8U9KBMMVY_c8FoHjSGR9GQbg,730
@@ -121,10 +121,10 @@ bbot/modules/iis_shortnames.py,sha256=bIlmC21a0eK_cjMu1UQkDl9EfpfCN1SAggDqJL8LJf
121
121
  bbot/modules/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
122
122
  bbot/modules/internal/aggregate.py,sha256=csWYIt2fUp9K_CRxP3bndUMIjpNIh8rmBubp5Fr1-nc,395
123
123
  bbot/modules/internal/base.py,sha256=BXO4Hc7XKaAOaLzolF3krJX1KibPxtek2GTQUgnCHk0,387
124
- bbot/modules/internal/cloudcheck.py,sha256=WVW5gQQhnJmTb1_wl4MjM_HUNQIKS8kIQFNKdaAGJiY,4754
125
- bbot/modules/internal/dnsresolve.py,sha256=EhZ9KI-cC4P0uIn09Qy7kpPhWU2seeOt-uYLsHqrcO4,15336
126
- bbot/modules/internal/excavate.py,sha256=18173N5g9xUZKwAPrvR6Y9Vm3WK_174s9YYBvSnqeZo,51527
127
- bbot/modules/internal/speculate.py,sha256=1UX5YKCfUnJ4EV8suHSAdq1Y2decEjIV88LQ8-VQcRQ,9260
124
+ bbot/modules/internal/cloudcheck.py,sha256=k9Sg7R06wV0hx0HJI86oWZ2ozeKa1S2VLpVPlx7XPe8,4845
125
+ bbot/modules/internal/dnsresolve.py,sha256=1fwWChIGpSEIIkswueiIhEwIahQ7YngZ-njFK-RIsfU,15679
126
+ bbot/modules/internal/excavate.py,sha256=IazekmFOnjrqghTf9YhBbMM4dohv27vIEvfNZXJSZvg,51529
127
+ bbot/modules/internal/speculate.py,sha256=NolqW2s8tokibc6gVM960KlrABkjhLB-7YlCdVx4O9s,9223
128
128
  bbot/modules/internetdb.py,sha256=Edg0Z84dH8dPTZMd7RlzvYBYNq8JHs_ns_ldnFxwRKo,5415
129
129
  bbot/modules/ip2location.py,sha256=yGivX9fzvwvLpnqmYCP2a8SPjTarzrZxfRluog-nkME,2628
130
130
  bbot/modules/ipneighbor.py,sha256=b_0IhorihFLtXJZEz57EGXjXW30gIOEzzVgz2GFvM3A,1591
@@ -144,17 +144,18 @@ bbot/modules/output/discord.py,sha256=BzZW0T-DgZHo3xwaQbZ6DAA59wKIvCDV1LK82ev7A2
144
144
  bbot/modules/output/emails.py,sha256=mzZideMCNfB8-naQANO5g8Y9HdgviAihRsdY_xPQjbQ,1095
145
145
  bbot/modules/output/http.py,sha256=4UWKpbQx3EHpi24VIem6oSvXr0W0NZ3lDpJOmQ3Mwik,2582
146
146
  bbot/modules/output/json.py,sha256=zvM2NwWScGk3pN4wF0mm-OqVW_0ADYy95Am4T02VVD4,1289
147
- bbot/modules/output/mysql.py,sha256=iq_VRvuarEZJHR8_OWB2Z76-yQrxWqNGfPrPHOi9oiI,1884
147
+ bbot/modules/output/mysql.py,sha256=mdIdu17otSuElA-_1OwnB3DV31lL0WcMrti38vqGsrY,1944
148
148
  bbot/modules/output/neo4j.py,sha256=u950eUwu8YMql_WaBA38TN2bUhx7xnZdIIvYfR3xVcY,6114
149
- bbot/modules/output/postgres.py,sha256=2JdEF6mU-VmVqPrgEh5L2MGv-s0BoNwoz8EnG5i3u2s,1847
149
+ bbot/modules/output/nmap_xml.py,sha256=RZx3LFNi_OWxd0lJXY6Nk-_sSQBRidRnoWKyZEaUXrQ,7048
150
+ bbot/modules/output/postgres.py,sha256=vsz3Gl9SKoWKhDidMFczksJzTeM0TZ7G9qY2rIYETF0,1938
150
151
  bbot/modules/output/python.py,sha256=RvK2KN-Zp0Vy_1zGSNioE5eeL5hIh6Z_riFtaTymyIM,270
151
152
  bbot/modules/output/slack.py,sha256=Ir_z11VYBdXDx8DwntWCv33Ic43vO1UIbxcp9gj0vvk,1181
152
153
  bbot/modules/output/splunk.py,sha256=TjTCUmDwRwKOFKBJw-Xbjku64U77OauHjtR56gyaAPs,1952
153
- bbot/modules/output/sqlite.py,sha256=GCtm1UoKfewtEKE79gBcj_UlTXO7jNHEEEuhqQ_iUnQ,888
154
- bbot/modules/output/stdout.py,sha256=d05QB4V4Rpw9dIZBwKlQsmdX8lSjeCt3uqkPPJYI5rY,3024
154
+ bbot/modules/output/sqlite.py,sha256=N0p6RRUcuCqGd4HIP0nG6JOPMs88LDQx4ImkdZVBM5E,979
155
+ bbot/modules/output/stdout.py,sha256=aLUtODqStdxmhh4lg7PRUsPEwTPLzdp3Hx7ZwbUvP_c,3084
155
156
  bbot/modules/output/subdomains.py,sha256=3KZz4vD0itmqpo56uCyk43Z_zN1Q0Q_nyXjdnEublPA,1515
156
157
  bbot/modules/output/teams.py,sha256=I2d52LqDC7e_oboLHoYBaRK6UpN0nkJ0uRnBXrhZf9E,4628
157
- bbot/modules/output/txt.py,sha256=_cQaa8oK0MAdF1YhWaZh_8szNneRpDqzFETta13HPB8,916
158
+ bbot/modules/output/txt.py,sha256=I4zGvsFvqYZtruiCLg5spAYwR-wqjxCU0FRkPhqBUJo,976
158
159
  bbot/modules/output/web_report.py,sha256=lZ0FqRZ7Jz1lljI9JMhH9gjtWLaTCSpSnAKQGAcPx-Q,3720
159
160
  bbot/modules/output/websocket.py,sha256=sDTtHU-Ey_tvS0gMi6PVPV9L4qAmGyWeccxAKfEWCac,2278
160
161
  bbot/modules/paramminer_cookies.py,sha256=q1PzftHQpCHLz81_VgLZsO6moia7ZtnU32igfcySi2w,1816
@@ -220,14 +221,14 @@ bbot/scanner/__init__.py,sha256=gCyAAbkNm8_KozNpDENCKqO3E3ZCgseplnz40AtiJ1U,56
220
221
  bbot/scanner/dispatcher.py,sha256=_hsIegfUDrt8CUdXqgRvp1J0UwwzqVSDxjQmiviO41c,793
221
222
  bbot/scanner/manager.py,sha256=_5FBfxOmSMUeGp_-ryyGGl0pxb_eu-NSWft-lH1Pyog,10466
222
223
  bbot/scanner/preset/__init__.py,sha256=Jf2hWsHlTFtWNXL6gXD8_ZbKPFUM564ppdSxHFYnIJU,27
223
- bbot/scanner/preset/args.py,sha256=KnFoQveKiSbNOSWr5dpa9lS3vP3Jnhk1FiyBLeaqFpI,16054
224
+ bbot/scanner/preset/args.py,sha256=pMJ0PfQDbLwOnggaKJl_CHz1SpQpqhhQQPvVWQaoIKA,16269
224
225
  bbot/scanner/preset/conditions.py,sha256=hFL9cSIWGEsv2TfM5UGurf0c91cyaM8egb5IngBmIjA,1569
225
226
  bbot/scanner/preset/environ.py,sha256=9KbEOLWkUdoAf5Ez_2A1NNm6QduQElbnNnrPi6VDhZs,4731
226
227
  bbot/scanner/preset/path.py,sha256=Q29MO8cOEn690yW6bB08P72kbZ3C-H_TOEoXuwWnFM8,2274
227
228
  bbot/scanner/preset/preset.py,sha256=R8-RNEstx4kLMZcfz878qzmTpEH45kgg3itRK-FWw5I,40038
228
229
  bbot/scanner/scanner.py,sha256=GTTimZPPjX7vFIAgmMpPcxnn4ZijHE3yjMEfTORKy88,53853
229
230
  bbot/scanner/stats.py,sha256=re93sArKXZSiD0Owgqk2J3Kdvfm3RL4Y9Qy_VOcaVk8,3623
230
- bbot/scanner/target.py,sha256=pxdICjl7Nl2aksTeFGtDilpW7EhLCIQtZJ7pertsPz4,11469
231
+ bbot/scanner/target.py,sha256=kYB2ItVzZDPaz1tj3iOe0LTkpntK7S8mfJ4qEJSOiSQ,11551
231
232
  bbot/scripts/docs.py,sha256=ZLY9-O6OeEElzOUvTglO5EMkRv1s4aEuxJb2CthCVsI,10782
232
233
  bbot/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
233
234
  bbot/test/bbot_fixtures.py,sha256=PNIycAMcNWM8oZ6BvvQmSbif1sztdOgyQ_e9lfQA6gA,9981
@@ -242,7 +243,7 @@ bbot/test/test_step_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
242
243
  bbot/test/test_step_1/test__module__tests.py,sha256=uwuROxdXI52D-V9z3Q9VNslvBfaduj6MQS5tQ_UOqXA,1460
243
244
  bbot/test/test_step_1/test_bbot_fastapi.py,sha256=FNGvlax4lFZVd0T3HvV9SJh1lsngOX58GrUnJVzoy20,2531
244
245
  bbot/test/test_step_1/test_bloom_filter.py,sha256=GodseGF98sarWXZ5C3JCVWblnycS4BA75HEAzhx4xXg,2139
245
- bbot/test/test_step_1/test_cli.py,sha256=JIBpAMpr2Zmg_cM0AOoyWLbwtF6JVhgp83Mxc1ZgPUs,25935
246
+ bbot/test/test_step_1/test_cli.py,sha256=osCnJFA5S7NpGeAukVFTx3EkmLZPX6vITectU062Rsg,26299
246
247
  bbot/test/test_step_1/test_command.py,sha256=5IeGV6TKB0xtFEsfsU_0mNrOmEdIQiQ3FHkUmsBNoOI,6485
247
248
  bbot/test/test_step_1/test_config.py,sha256=Q38hygpke2GDcv8OguVZuiSOnfDJxEMrRy20dN5Qsn0,887
248
249
  bbot/test/test_step_1/test_depsinstaller.py,sha256=zr9f-wJDotD1ZvKXGEuDRWzFYMAYBI6209mI_PWPtTQ,703
@@ -254,13 +255,13 @@ bbot/test/test_step_1/test_files.py,sha256=5Q_3jPpMXULxDHsanSDUaj8zF8bXzKdiJZHOm
254
255
  bbot/test/test_step_1/test_helpers.py,sha256=6WG2rqnI7Jt0Z7Dc5AyqTDcL16QM0_WJ3CXE1M-xSMc,39506
255
256
  bbot/test/test_step_1/test_manager_deduplication.py,sha256=hZQpDXzg6zvzxFolVOcJuY-ME8NXjZUsqS70BRNXp8A,15594
256
257
  bbot/test/test_step_1/test_manager_scope_accuracy.py,sha256=JV1bQHt9EIM0GmGS4T4Brz_L2lfcwTxtNC06cfv7r64,79763
257
- bbot/test/test_step_1/test_modules_basic.py,sha256=PtY8plupy-eOAr3YHWAZtgKqNRZt2eYtJljY8Zf3Cuo,20055
258
+ bbot/test/test_step_1/test_modules_basic.py,sha256=hxXdsrBwme5elGQtvyvA52-KzahyQC3FlWQZ3T0EheA,19989
258
259
  bbot/test/test_step_1/test_presets.py,sha256=CCwXb0gxTd8lSYtp0a_2PkfrwfdD5f9VngetbCLecL0,38211
259
260
  bbot/test/test_step_1/test_python_api.py,sha256=GM5Kp2AAFl92ozo1kL6axsM87F8Gdq2_mWQvRnbXW_0,5503
260
261
  bbot/test/test_step_1/test_regexes.py,sha256=34-BHzDE5qdltE-sQIzkrTmJTL49QUYoTn2uT1DZLwI,14356
261
262
  bbot/test/test_step_1/test_scan.py,sha256=h3JP5RXnOUH8dqqq2Q_7yLpx1LCAEvqfE1bpHL7bDS0,5756
262
263
  bbot/test/test_step_1/test_scope.py,sha256=S2nssENKJKCvgXUMyU8MFQmXHeUIz0C_sbWGkdYti2A,3063
263
- bbot/test/test_step_1/test_target.py,sha256=Kd-tk9033GIQR9mlJ2a5y-4_YtC9XCOmjx6dcgu78qs,19084
264
+ bbot/test/test_step_1/test_target.py,sha256=O-r7WxLdO6C3FmhjhA9rfRWb3uX4xW0eEQX4qCMFG7Q,19127
264
265
  bbot/test/test_step_1/test_web.py,sha256=n9p9WhsEyN5I7S8RUUOEzF8v1CyeJjkmk4l6hnpOblY,18804
265
266
  bbot/test/test_step_2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
266
267
  bbot/test/test_step_2/module_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -350,6 +351,7 @@ bbot/test/test_step_2/module_tests/test_module_mysql.py,sha256=4wAPjbjhlxmOkEhQn
350
351
  bbot/test/test_step_2/module_tests/test_module_myssl.py,sha256=zRJ1sOEespWtBx2jA07bW5sHD1XQ9pV0PtHtGogo7Gs,1531
351
352
  bbot/test/test_step_2/module_tests/test_module_neo4j.py,sha256=pUUaqxBsF6s11dEDhrETpvlR2pqiUcc0uvH8Z5GvVUQ,1332
352
353
  bbot/test/test_step_2/module_tests/test_module_newsletters.py,sha256=uf5t2oRqxhNToPjEfkY9vMdOUzrSocvx8w5itS6HUaM,2295
354
+ bbot/test/test_step_2/module_tests/test_module_nmap_xml.py,sha256=KbUAjhARvtERv7Jx666n2hkuLOmK8Zah8RpLZqNyAuE,3548
353
355
  bbot/test/test_step_2/module_tests/test_module_ntlm.py,sha256=tPUrsOnq8iV0l_qiD_4xkqp0-o_T2uI1e-yH22oNveA,1132
354
356
  bbot/test/test_step_2/module_tests/test_module_nuclei.py,sha256=rLCTuKWnGWiGDcVnMjk4D7x6RGftEj3D4Woqpam-cgQ,7050
355
357
  bbot/test/test_step_2/module_tests/test_module_oauth.py,sha256=pN1o0DmcwGCa985FrIhUuX1jIGriDjaxMzWozuv8pR0,9481
@@ -414,8 +416,8 @@ bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt,sha256=ZSIVebs7ptMvHx
414
416
  bbot/wordlists/top_open_ports_nmap.txt,sha256=LmdFYkfapSxn1pVuQC2LkOIY2hMLgG-Xts7DVtYzweM,42727
415
417
  bbot/wordlists/valid_url_schemes.txt,sha256=0B_VAr9Dv7aYhwi6JSBDU-3M76vNtzN0qEC_RNLo7HE,3310
416
418
  bbot/wordlists/wordninja_dns.txt.gz,sha256=DYHvvfW0TvzrVwyprqODAk4tGOxv5ezNmCPSdPuDUnQ,570241
417
- bbot-2.3.0.5418rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
418
- bbot-2.3.0.5418rc0.dist-info/METADATA,sha256=_i6aZZx3cPBTqNqTXbUxrAVoqzSrIN4zIBlk0YGxCyQ,17949
419
- bbot-2.3.0.5418rc0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
420
- bbot-2.3.0.5418rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
421
- bbot-2.3.0.5418rc0.dist-info/RECORD,,
419
+ bbot-2.3.0.5438rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
420
+ bbot-2.3.0.5438rc0.dist-info/METADATA,sha256=i5UQgB9yhkyfzqgT3X74QNPpmFrdp0oZcTsLXFWUzcg,17949
421
+ bbot-2.3.0.5438rc0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
422
+ bbot-2.3.0.5438rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
423
+ bbot-2.3.0.5438rc0.dist-info/RECORD,,