bbot 2.1.0.5004rc0__py3-none-any.whl → 2.1.0.5028rc0__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.
- bbot/__init__.py +1 -1
- bbot/core/event/base.py +21 -4
- bbot/core/helpers/misc.py +10 -3
- bbot/core/helpers/regexes.py +3 -0
- bbot/modules/base.py +4 -1
- bbot/modules/generic_ssrf.py +2 -2
- bbot/modules/internal/dnsresolve.py +0 -6
- bbot/modules/internal/excavate.py +2 -0
- bbot/modules/internal/speculate.py +3 -4
- bbot/modules/shodan_dns.py +7 -9
- bbot/modules/templates/subdomain_enum.py +43 -4
- bbot/modules/trickest.py +4 -28
- bbot/modules/virustotal.py +4 -14
- bbot/scanner/preset/preset.py +0 -2
- bbot/scanner/scanner.py +13 -11
- bbot/test/test_step_1/test_cli.py +0 -8
- bbot/test/test_step_1/test_events.py +36 -7
- bbot/test/test_step_1/test_helpers.py +15 -2
- bbot/test/test_step_1/test_manager_scope_accuracy.py +9 -7
- bbot/test/test_step_1/test_modules_basic.py +7 -6
- bbot/test/test_step_1/test_presets.py +21 -3
- bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +20 -1
- {bbot-2.1.0.5004rc0.dist-info → bbot-2.1.0.5028rc0.dist-info}/METADATA +1 -1
- {bbot-2.1.0.5004rc0.dist-info → bbot-2.1.0.5028rc0.dist-info}/RECORD +27 -27
- {bbot-2.1.0.5004rc0.dist-info → bbot-2.1.0.5028rc0.dist-info}/LICENSE +0 -0
- {bbot-2.1.0.5004rc0.dist-info → bbot-2.1.0.5028rc0.dist-info}/WHEEL +0 -0
- {bbot-2.1.0.5004rc0.dist-info → bbot-2.1.0.5028rc0.dist-info}/entry_points.txt +0 -0
bbot/__init__.py
CHANGED
bbot/core/event/base.py
CHANGED
|
@@ -25,6 +25,7 @@ from bbot.core.helpers import (
|
|
|
25
25
|
is_domain,
|
|
26
26
|
is_subdomain,
|
|
27
27
|
is_ip,
|
|
28
|
+
is_ip_type,
|
|
28
29
|
is_ptr,
|
|
29
30
|
is_uri,
|
|
30
31
|
url_depth,
|
|
@@ -157,7 +158,7 @@ class BaseEvent:
|
|
|
157
158
|
Raises:
|
|
158
159
|
ValidationError: If either `scan` or `parent` are not specified and `_dummy` is False.
|
|
159
160
|
"""
|
|
160
|
-
self.
|
|
161
|
+
self._uuid = uuid.uuid4()
|
|
161
162
|
self._id = None
|
|
162
163
|
self._hash = None
|
|
163
164
|
self._data = None
|
|
@@ -352,6 +353,12 @@ class BaseEvent:
|
|
|
352
353
|
return 80
|
|
353
354
|
return self._port
|
|
354
355
|
|
|
356
|
+
@property
|
|
357
|
+
def netloc(self):
|
|
358
|
+
if self.host and is_ip_type(self.host, network=False):
|
|
359
|
+
return make_netloc(self.host, self.port)
|
|
360
|
+
return None
|
|
361
|
+
|
|
355
362
|
@property
|
|
356
363
|
def host_stem(self):
|
|
357
364
|
"""
|
|
@@ -449,6 +456,13 @@ class BaseEvent:
|
|
|
449
456
|
self._id = f"{self.type}:{self.data_hash.hex()}"
|
|
450
457
|
return self._id
|
|
451
458
|
|
|
459
|
+
@property
|
|
460
|
+
def uuid(self):
|
|
461
|
+
"""
|
|
462
|
+
A universally unique identifier for the event
|
|
463
|
+
"""
|
|
464
|
+
return f"{self.type}:{self._uuid}"
|
|
465
|
+
|
|
452
466
|
@property
|
|
453
467
|
def data_hash(self):
|
|
454
468
|
"""
|
|
@@ -741,7 +755,7 @@ class BaseEvent:
|
|
|
741
755
|
"""
|
|
742
756
|
j = dict()
|
|
743
757
|
# type, ID, scope description
|
|
744
|
-
for i in ("type", "id", "uuid", "scope_description"):
|
|
758
|
+
for i in ("type", "id", "uuid", "scope_description", "netloc"):
|
|
745
759
|
v = getattr(self, i, "")
|
|
746
760
|
if v:
|
|
747
761
|
j.update({i: str(v)})
|
|
@@ -760,6 +774,8 @@ class BaseEvent:
|
|
|
760
774
|
j["host"] = str(self.host)
|
|
761
775
|
j["resolved_hosts"] = sorted(str(h) for h in self.resolved_hosts)
|
|
762
776
|
j["dns_children"] = {k: list(v) for k, v in self.dns_children.items()}
|
|
777
|
+
if isinstance(self.port, int):
|
|
778
|
+
j["port"] = self.port
|
|
763
779
|
# web spider distance
|
|
764
780
|
web_spider_distance = getattr(self, "web_spider_distance", None)
|
|
765
781
|
if web_spider_distance is not None:
|
|
@@ -1709,7 +1725,7 @@ def event_from_json(j, siem_friendly=False):
|
|
|
1709
1725
|
event = make_event(**kwargs)
|
|
1710
1726
|
event_uuid = j.get("uuid", None)
|
|
1711
1727
|
if event_uuid is not None:
|
|
1712
|
-
event.
|
|
1728
|
+
event._uuid = uuid.UUID(event_uuid.split(":")[-1])
|
|
1713
1729
|
|
|
1714
1730
|
resolved_hosts = j.get("resolved_hosts", [])
|
|
1715
1731
|
event._resolved_hosts = set(resolved_hosts)
|
|
@@ -1721,7 +1737,8 @@ def event_from_json(j, siem_friendly=False):
|
|
|
1721
1737
|
event._parent_id = parent_id
|
|
1722
1738
|
parent_uuid = j.get("parent_uuid", None)
|
|
1723
1739
|
if parent_uuid is not None:
|
|
1724
|
-
|
|
1740
|
+
parent_type, parent_uuid = parent_uuid.split(":", 1)
|
|
1741
|
+
event._parent_uuid = parent_type + ":" + str(uuid.UUID(parent_uuid))
|
|
1725
1742
|
return event
|
|
1726
1743
|
except KeyError as e:
|
|
1727
1744
|
raise ValidationError(f"Event missing required field: {e}")
|
bbot/core/helpers/misc.py
CHANGED
|
@@ -621,12 +621,13 @@ def is_ip(d, version=None):
|
|
|
621
621
|
return False
|
|
622
622
|
|
|
623
623
|
|
|
624
|
-
def is_ip_type(i):
|
|
624
|
+
def is_ip_type(i, network=None):
|
|
625
625
|
"""
|
|
626
626
|
Checks if the given object is an instance of an IPv4 or IPv6 type from the ipaddress module.
|
|
627
627
|
|
|
628
628
|
Args:
|
|
629
629
|
i (ipaddress._BaseV4 or ipaddress._BaseV6): The IP object to check.
|
|
630
|
+
network (bool, optional): Whether to restrict the check to network types (IPv4Network or IPv6Network). Defaults to False.
|
|
630
631
|
|
|
631
632
|
Returns:
|
|
632
633
|
bool: True if the object is an instance of ipaddress._BaseV4 or ipaddress._BaseV6, False otherwise.
|
|
@@ -639,6 +640,12 @@ def is_ip_type(i):
|
|
|
639
640
|
>>> is_ip_type("192.168.1.0/24")
|
|
640
641
|
False
|
|
641
642
|
"""
|
|
643
|
+
if network is not None:
|
|
644
|
+
is_network = ipaddress._BaseNetwork in i.__class__.__mro__
|
|
645
|
+
if network:
|
|
646
|
+
return is_network
|
|
647
|
+
else:
|
|
648
|
+
return not is_network
|
|
642
649
|
return ipaddress._IPAddressBase in i.__class__.__mro__
|
|
643
650
|
|
|
644
651
|
|
|
@@ -1260,7 +1267,7 @@ def gen_numbers(n, padding=2):
|
|
|
1260
1267
|
return results
|
|
1261
1268
|
|
|
1262
1269
|
|
|
1263
|
-
def make_netloc(host, port):
|
|
1270
|
+
def make_netloc(host, port=None):
|
|
1264
1271
|
"""Constructs a network location string from a given host and port.
|
|
1265
1272
|
|
|
1266
1273
|
Args:
|
|
@@ -1289,7 +1296,7 @@ def make_netloc(host, port):
|
|
|
1289
1296
|
if is_ip(host, version=6):
|
|
1290
1297
|
host = f"[{host}]"
|
|
1291
1298
|
if port is None:
|
|
1292
|
-
return host
|
|
1299
|
+
return str(host)
|
|
1293
1300
|
return f"{host}:{port}"
|
|
1294
1301
|
|
|
1295
1302
|
|
bbot/core/helpers/regexes.py
CHANGED
|
@@ -54,6 +54,9 @@ ptr_regex = re.compile(_ptr_regex)
|
|
|
54
54
|
# uuid regex
|
|
55
55
|
_uuid_regex = r"[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}"
|
|
56
56
|
uuid_regex = re.compile(_uuid_regex, re.I)
|
|
57
|
+
# event uuid regex
|
|
58
|
+
_event_uuid_regex = r"[0-9A-Z_]+:[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}"
|
|
59
|
+
event_uuid_regex = re.compile(_event_uuid_regex, re.I)
|
|
57
60
|
|
|
58
61
|
_open_port_regexes = (
|
|
59
62
|
_dns_name_regex + r":[0-9]{1,5}",
|
bbot/modules/base.py
CHANGED
|
@@ -984,8 +984,11 @@ class BaseModule:
|
|
|
984
984
|
def _outgoing_dedup_hash(self, event):
|
|
985
985
|
"""
|
|
986
986
|
Determines the criteria for what is considered to be a duplicate event if `suppress_dupes` is True.
|
|
987
|
+
|
|
988
|
+
We take into account the `internal` attribute we don't want an internal event (which isn't distributed to output modules)
|
|
989
|
+
to inadvertently suppress a non-internal event.
|
|
987
990
|
"""
|
|
988
|
-
return hash((event, self.name))
|
|
991
|
+
return hash((event, self.name, event.internal, event.always_emit))
|
|
989
992
|
|
|
990
993
|
def get_per_host_hash(self, event):
|
|
991
994
|
"""
|
bbot/modules/generic_ssrf.py
CHANGED
|
@@ -137,10 +137,10 @@ class Generic_XXE(BaseSubmodule):
|
|
|
137
137
|
post_body = f"""<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
138
138
|
<!DOCTYPE foo [
|
|
139
139
|
<!ELEMENT foo ANY >
|
|
140
|
-
<!ENTITY
|
|
140
|
+
<!ENTITY {rand_entity} SYSTEM "http://{subdomain_tag}.{self.parent_module.interactsh_domain}" >
|
|
141
141
|
]>
|
|
142
142
|
<foo>&{rand_entity};</foo>"""
|
|
143
|
-
test_url =
|
|
143
|
+
test_url = event.parsed_url.geturl()
|
|
144
144
|
r = await self.parent_module.helpers.curl(
|
|
145
145
|
url=test_url, method="POST", raw_body=post_body, headers={"Content-type": "application/xml"}
|
|
146
146
|
)
|
|
@@ -16,12 +16,6 @@ class DNSResolve(BaseInterceptModule):
|
|
|
16
16
|
_name = "host"
|
|
17
17
|
_type = "internal"
|
|
18
18
|
|
|
19
|
-
def _outgoing_dedup_hash(self, event):
|
|
20
|
-
# this exists to ensure a second, more interesting host isn't passed up
|
|
21
|
-
# because its ugly cousin spent its one dedup token before it arrived
|
|
22
|
-
# by removing those race conditions, this makes for more consistent results
|
|
23
|
-
return hash((event, self.name, event.always_emit))
|
|
24
|
-
|
|
25
19
|
@property
|
|
26
20
|
def module_threads(self):
|
|
27
21
|
return self.dns_config.get("threads", 25)
|
|
@@ -876,6 +876,8 @@ class excavate(BaseInternalModule, BaseInterceptModule):
|
|
|
876
876
|
yara_rules_combined = "\n".join(self.yara_rules_dict.values())
|
|
877
877
|
try:
|
|
878
878
|
self.info(f"Compiling {len(self.yara_rules_dict):,} YARA rules")
|
|
879
|
+
for rule_name, rule_content in self.yara_rules_dict.items():
|
|
880
|
+
self.debug(f" - {rule_name}")
|
|
879
881
|
self.yara_rules = yara.compile(source=yara_rules_combined)
|
|
880
882
|
except yara.SyntaxError as e:
|
|
881
883
|
self.debug(yara_rules_combined)
|
|
@@ -112,15 +112,15 @@ class speculate(BaseInternalModule):
|
|
|
112
112
|
speculate_open_ports = self.emit_open_ports and event_in_scope_distance
|
|
113
113
|
|
|
114
114
|
# URL --> OPEN_TCP_PORT
|
|
115
|
-
|
|
115
|
+
event_is_url = event.type == "URL"
|
|
116
|
+
if event_is_url or (event.type == "URL_UNVERIFIED" and self.open_port_consumers):
|
|
116
117
|
# only speculate port from a URL if it wouldn't be speculated naturally from the host
|
|
117
118
|
if event.host and (event.port not in self.ports or not speculate_open_ports):
|
|
118
119
|
await self.emit_event(
|
|
119
120
|
self.helpers.make_netloc(event.host, event.port),
|
|
120
121
|
"OPEN_TCP_PORT",
|
|
121
122
|
parent=event,
|
|
122
|
-
internal=
|
|
123
|
-
quick=(event.type == "URL"),
|
|
123
|
+
internal=not event_is_url, # if the URL is verified, the port is definitely open
|
|
124
124
|
context=f"speculated {{event.type}} from {event.type}: {{event.data}}",
|
|
125
125
|
)
|
|
126
126
|
|
|
@@ -169,7 +169,6 @@ class speculate(BaseInternalModule):
|
|
|
169
169
|
"OPEN_TCP_PORT",
|
|
170
170
|
parent=event,
|
|
171
171
|
internal=True,
|
|
172
|
-
quick=True,
|
|
173
172
|
context="speculated {event.type}: {event.data}",
|
|
174
173
|
)
|
|
175
174
|
|
bbot/modules/shodan_dns.py
CHANGED
|
@@ -16,13 +16,11 @@ class shodan_dns(shodan):
|
|
|
16
16
|
|
|
17
17
|
base_url = "https://api.shodan.io"
|
|
18
18
|
|
|
19
|
-
async def
|
|
20
|
-
|
|
21
|
-
response = await self.api_request(url)
|
|
22
|
-
return response
|
|
19
|
+
async def handle_event(self, event):
|
|
20
|
+
await self.handle_event_paginated(event)
|
|
23
21
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
def make_url(self, query):
|
|
23
|
+
return f"{self.base_url}/dns/domain/{self.helpers.quote(query)}?key={{api_key}}&page={{page}}"
|
|
24
|
+
|
|
25
|
+
def parse_results(self, json, query):
|
|
26
|
+
return [f"{sub}.{query}" for sub in json.get("subdomains", [])]
|
|
@@ -31,6 +31,11 @@ class subdomain_enum(BaseModule):
|
|
|
31
31
|
# "lowest_parent": dedupe by lowest parent (lowest parent of www.api.test.evilcorp.com is api.test.evilcorp.com)
|
|
32
32
|
dedup_strategy = "highest_parent"
|
|
33
33
|
|
|
34
|
+
# how many results to request per API call
|
|
35
|
+
page_size = 100
|
|
36
|
+
# arguments to pass to api_page_iter
|
|
37
|
+
api_page_iter_kwargs = {}
|
|
38
|
+
|
|
34
39
|
@property
|
|
35
40
|
def source_pretty_name(self):
|
|
36
41
|
return f"{self.__class__.__name__} API"
|
|
@@ -61,10 +66,31 @@ class subdomain_enum(BaseModule):
|
|
|
61
66
|
context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.data}}',
|
|
62
67
|
)
|
|
63
68
|
|
|
69
|
+
async def handle_event_paginated(self, event):
|
|
70
|
+
query = self.make_query(event)
|
|
71
|
+
async for result_batch in self.query_paginated(query):
|
|
72
|
+
for hostname in set(result_batch):
|
|
73
|
+
try:
|
|
74
|
+
hostname = self.helpers.validators.validate_host(hostname)
|
|
75
|
+
except ValueError as e:
|
|
76
|
+
self.verbose(e)
|
|
77
|
+
continue
|
|
78
|
+
if hostname and hostname.endswith(f".{query}") and not hostname == event.data:
|
|
79
|
+
await self.emit_event(
|
|
80
|
+
hostname,
|
|
81
|
+
"DNS_NAME",
|
|
82
|
+
event,
|
|
83
|
+
abort_if=self.abort_if,
|
|
84
|
+
context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.data}}',
|
|
85
|
+
)
|
|
86
|
+
|
|
64
87
|
async def request_url(self, query):
|
|
65
|
-
url =
|
|
88
|
+
url = self.make_url(query)
|
|
66
89
|
return await self.api_request(url)
|
|
67
90
|
|
|
91
|
+
def make_url(self, query):
|
|
92
|
+
return f"{self.base_url}/subdomains/{self.helpers.quote(query)}"
|
|
93
|
+
|
|
68
94
|
def make_query(self, event):
|
|
69
95
|
query = event.data
|
|
70
96
|
parents = list(self.helpers.domain_parents(event.data))
|
|
@@ -86,11 +112,11 @@ class subdomain_enum(BaseModule):
|
|
|
86
112
|
for hostname in json:
|
|
87
113
|
yield hostname
|
|
88
114
|
|
|
89
|
-
async def query(self, query,
|
|
90
|
-
if parse_fn is None:
|
|
91
|
-
parse_fn = self.parse_results
|
|
115
|
+
async def query(self, query, request_fn=None, parse_fn=None):
|
|
92
116
|
if request_fn is None:
|
|
93
117
|
request_fn = self.request_url
|
|
118
|
+
if parse_fn is None:
|
|
119
|
+
parse_fn = self.parse_results
|
|
94
120
|
try:
|
|
95
121
|
response = await request_fn(query)
|
|
96
122
|
if response is None:
|
|
@@ -113,6 +139,19 @@ class subdomain_enum(BaseModule):
|
|
|
113
139
|
except Exception as e:
|
|
114
140
|
self.info(f"Error retrieving results for {query}: {e}", trace=True)
|
|
115
141
|
|
|
142
|
+
async def query_paginated(self, query):
|
|
143
|
+
url = self.make_url(query)
|
|
144
|
+
agen = self.api_page_iter(url, page_size=self.page_size, **self.api_page_iter_kwargs)
|
|
145
|
+
try:
|
|
146
|
+
async for response in agen:
|
|
147
|
+
subdomains = self.parse_results(response, query)
|
|
148
|
+
self.verbose(f'Got {len(subdomains):,} subdomains for "{query}"')
|
|
149
|
+
if not subdomains:
|
|
150
|
+
break
|
|
151
|
+
yield subdomains
|
|
152
|
+
finally:
|
|
153
|
+
agen.aclose()
|
|
154
|
+
|
|
116
155
|
async def _is_wildcard(self, query):
|
|
117
156
|
rdtypes = ("A", "AAAA", "CNAME")
|
|
118
157
|
if self.helpers.is_dns_name(query):
|
bbot/modules/trickest.py
CHANGED
|
@@ -28,39 +28,15 @@ class Trickest(subdomain_enum_apikey):
|
|
|
28
28
|
return url, kwargs
|
|
29
29
|
|
|
30
30
|
async def handle_event(self, event):
|
|
31
|
-
|
|
32
|
-
async for result_batch in self.query(query):
|
|
33
|
-
for hostname in set(result_batch):
|
|
34
|
-
try:
|
|
35
|
-
hostname = self.helpers.validators.validate_host(hostname)
|
|
36
|
-
except ValueError as e:
|
|
37
|
-
self.verbose(e)
|
|
38
|
-
continue
|
|
39
|
-
if hostname and hostname.endswith(f".{query}") and not hostname == event.data:
|
|
40
|
-
await self.emit_event(
|
|
41
|
-
hostname,
|
|
42
|
-
"DNS_NAME",
|
|
43
|
-
event,
|
|
44
|
-
abort_if=self.abort_if,
|
|
45
|
-
context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.data}}',
|
|
46
|
-
)
|
|
31
|
+
await self.handle_event_paginated(event)
|
|
47
32
|
|
|
48
|
-
|
|
33
|
+
def make_url(self, query):
|
|
49
34
|
url = f"{self.base_url}/view?q=hostname%20~%20%22.{self.helpers.quote(query)}%22"
|
|
50
35
|
url += f"&dataset_id={self.dataset_id}"
|
|
51
36
|
url += "&limit={page_size}&offset={offset}&select=hostname&orderby=hostname"
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
async for response in agen:
|
|
55
|
-
subdomains = self.parse_results(response)
|
|
56
|
-
self.verbose(f'Got {len(subdomains):,} subdomains for "{query}"')
|
|
57
|
-
if not subdomains:
|
|
58
|
-
break
|
|
59
|
-
yield subdomains
|
|
60
|
-
finally:
|
|
61
|
-
agen.aclose()
|
|
37
|
+
return url
|
|
62
38
|
|
|
63
|
-
def parse_results(self, j):
|
|
39
|
+
def parse_results(self, j, query):
|
|
64
40
|
results = j.get("results", [])
|
|
65
41
|
subdomains = set()
|
|
66
42
|
for item in results:
|
bbot/modules/virustotal.py
CHANGED
|
@@ -15,6 +15,10 @@ class virustotal(subdomain_enum_apikey):
|
|
|
15
15
|
options_desc = {"api_key": "VirusTotal API Key"}
|
|
16
16
|
|
|
17
17
|
base_url = "https://www.virustotal.com/api/v3"
|
|
18
|
+
api_page_iter_kwargs = {"json": False, "next_key": lambda r: r.json().get("links", {}).get("next", "")}
|
|
19
|
+
|
|
20
|
+
def make_url(self, query):
|
|
21
|
+
return f"{self.base_url}/domains/{self.helpers.quote(query)}/subdomains"
|
|
18
22
|
|
|
19
23
|
def prepare_api_request(self, url, kwargs):
|
|
20
24
|
kwargs["headers"]["x-apikey"] = self.api_key
|
|
@@ -28,17 +32,3 @@ class virustotal(subdomain_enum_apikey):
|
|
|
28
32
|
if match.endswith(query):
|
|
29
33
|
results.add(match)
|
|
30
34
|
return results
|
|
31
|
-
|
|
32
|
-
async def query(self, query):
|
|
33
|
-
results = set()
|
|
34
|
-
url = f"{self.base_url}/domains/{self.helpers.quote(query)}/subdomains"
|
|
35
|
-
agen = self.api_page_iter(url, json=False, next_key=lambda r: r.json().get("links", {}).get("next", ""))
|
|
36
|
-
try:
|
|
37
|
-
async for response in agen:
|
|
38
|
-
r = self.parse_results(response, query)
|
|
39
|
-
if not r:
|
|
40
|
-
break
|
|
41
|
-
results.update(r)
|
|
42
|
-
finally:
|
|
43
|
-
agen.aclose()
|
|
44
|
-
return results
|
bbot/scanner/preset/preset.py
CHANGED
|
@@ -844,8 +844,6 @@ class Preset:
|
|
|
844
844
|
|
|
845
845
|
if module in self.exclude_modules:
|
|
846
846
|
reason = "the module has been excluded"
|
|
847
|
-
if raise_error:
|
|
848
|
-
raise ValidationError(f'Unable to add {module_type} module "{module}" because {reason}')
|
|
849
847
|
return False, reason, {}
|
|
850
848
|
|
|
851
849
|
module_flags = preloaded.get("flags", [])
|
bbot/scanner/scanner.py
CHANGED
|
@@ -130,20 +130,22 @@ class Scanner:
|
|
|
130
130
|
else:
|
|
131
131
|
self.id = f"SCAN:{sha1(rand_string(20)).hexdigest()}"
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
custom_preset = kwargs.pop("preset", None)
|
|
134
134
|
kwargs["_log"] = True
|
|
135
135
|
|
|
136
136
|
from .preset import Preset
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if not isinstance(
|
|
142
|
-
raise ValidationError(f'Preset must be of type Preset, not "{type(
|
|
143
|
-
|
|
138
|
+
base_preset = Preset(*targets, **kwargs)
|
|
139
|
+
|
|
140
|
+
if custom_preset is not None:
|
|
141
|
+
if not isinstance(custom_preset, Preset):
|
|
142
|
+
raise ValidationError(f'Preset must be of type Preset, not "{type(custom_preset).__name__}"')
|
|
143
|
+
base_preset.merge(custom_preset)
|
|
144
|
+
|
|
145
|
+
self.preset = base_preset.bake(self)
|
|
144
146
|
|
|
145
147
|
# scan name
|
|
146
|
-
if preset.scan_name is None:
|
|
148
|
+
if self.preset.scan_name is None:
|
|
147
149
|
tries = 0
|
|
148
150
|
while 1:
|
|
149
151
|
if tries > 5:
|
|
@@ -158,7 +160,7 @@ class Scanner:
|
|
|
158
160
|
break
|
|
159
161
|
tries += 1
|
|
160
162
|
else:
|
|
161
|
-
scan_name = str(preset.scan_name)
|
|
163
|
+
scan_name = str(self.preset.scan_name)
|
|
162
164
|
self.name = scan_name
|
|
163
165
|
|
|
164
166
|
# make sure the preset has a description
|
|
@@ -166,8 +168,8 @@ class Scanner:
|
|
|
166
168
|
self.preset.description = self.name
|
|
167
169
|
|
|
168
170
|
# scan output dir
|
|
169
|
-
if preset.output_dir is not None:
|
|
170
|
-
self.home = Path(preset.output_dir).resolve() / self.name
|
|
171
|
+
if self.preset.output_dir is not None:
|
|
172
|
+
self.home = Path(self.preset.output_dir).resolve() / self.name
|
|
171
173
|
else:
|
|
172
174
|
self.home = self.preset.bbot_home / "scans" / self.name
|
|
173
175
|
|
|
@@ -351,14 +351,6 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config):
|
|
|
351
351
|
result = await cli._main()
|
|
352
352
|
assert result == True
|
|
353
353
|
|
|
354
|
-
# enable and exclude the same module
|
|
355
|
-
caplog.clear()
|
|
356
|
-
assert not caplog.text
|
|
357
|
-
monkeypatch.setattr("sys.argv", ["bbot", "-m", "ffuf_shortnames", "-em", "ffuf_shortnames"])
|
|
358
|
-
result = await cli._main()
|
|
359
|
-
assert result == None
|
|
360
|
-
assert 'Unable to add scan module "ffuf_shortnames" because the module has been excluded' in caplog.text
|
|
361
|
-
|
|
362
354
|
# require flags
|
|
363
355
|
monkeypatch.setattr("sys.argv", ["bbot", "-f", "active", "-rf", "passive"])
|
|
364
356
|
result = await cli._main()
|
|
@@ -4,7 +4,7 @@ import ipaddress
|
|
|
4
4
|
|
|
5
5
|
from ..bbot_fixtures import *
|
|
6
6
|
from bbot.scanner import Scanner
|
|
7
|
-
from bbot.core.helpers.regexes import
|
|
7
|
+
from bbot.core.helpers.regexes import event_uuid_regex
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@pytest.mark.asyncio
|
|
@@ -14,10 +14,19 @@ async def test_events(events, helpers):
|
|
|
14
14
|
await scan._prep()
|
|
15
15
|
|
|
16
16
|
assert events.ipv4.type == "IP_ADDRESS"
|
|
17
|
+
assert events.ipv4.netloc == "8.8.8.8"
|
|
18
|
+
assert events.ipv4.port is None
|
|
17
19
|
assert events.ipv6.type == "IP_ADDRESS"
|
|
20
|
+
assert events.ipv6.netloc == "[2001:4860:4860::8888]"
|
|
21
|
+
assert events.ipv6.port is None
|
|
22
|
+
assert events.ipv6_open_port.netloc == "[2001:4860:4860::8888]:443"
|
|
18
23
|
assert events.netv4.type == "IP_RANGE"
|
|
24
|
+
assert events.netv4.netloc is None
|
|
25
|
+
assert "netloc" not in events.netv4.json()
|
|
19
26
|
assert events.netv6.type == "IP_RANGE"
|
|
20
27
|
assert events.domain.type == "DNS_NAME"
|
|
28
|
+
assert events.domain.netloc == "publicapis.org"
|
|
29
|
+
assert events.domain.port is None
|
|
21
30
|
assert "domain" in events.domain.tags
|
|
22
31
|
assert events.subdomain.type == "DNS_NAME"
|
|
23
32
|
assert "subdomain" in events.subdomain.tags
|
|
@@ -67,8 +76,14 @@ async def test_events(events, helpers):
|
|
|
67
76
|
assert not events.netv6 in events.domain
|
|
68
77
|
assert events.emoji not in events.domain
|
|
69
78
|
assert events.domain not in events.emoji
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
open_port_event = scan.make_event(" eViLcorp.COM.:88", "DNS_NAME", dummy=True)
|
|
80
|
+
dns_event = scan.make_event("evilcorp.com.", "DNS_NAME", dummy=True)
|
|
81
|
+
for e in (open_port_event, dns_event):
|
|
82
|
+
assert "evilcorp.com" == e
|
|
83
|
+
assert e.netloc == "evilcorp.com"
|
|
84
|
+
assert e.json()["netloc"] == "evilcorp.com"
|
|
85
|
+
assert e.port is None
|
|
86
|
+
assert "port" not in e.json()
|
|
72
87
|
|
|
73
88
|
# url tests
|
|
74
89
|
assert scan.make_event("http://evilcorp.com", dummy=True) == scan.make_event("http://evilcorp.com/", dummy=True)
|
|
@@ -78,8 +93,14 @@ async def test_events(events, helpers):
|
|
|
78
93
|
assert "api.publicapis.org:443" in events.url_unverified
|
|
79
94
|
assert "publicapis.org" not in events.url_unverified
|
|
80
95
|
assert events.ipv4_url_unverified in events.ipv4
|
|
96
|
+
assert events.ipv4_url_unverified.netloc == "8.8.8.8:443"
|
|
97
|
+
assert events.ipv4_url_unverified.port == 443
|
|
98
|
+
assert events.ipv4_url_unverified.json()["port"] == 443
|
|
81
99
|
assert events.ipv4_url_unverified in events.netv4
|
|
82
100
|
assert events.ipv6_url_unverified in events.ipv6
|
|
101
|
+
assert events.ipv6_url_unverified.netloc == "[2001:4860:4860::8888]:443"
|
|
102
|
+
assert events.ipv6_url_unverified.port == 443
|
|
103
|
+
assert events.ipv6_url_unverified.json()["port"] == 443
|
|
83
104
|
assert events.ipv6_url_unverified in events.netv6
|
|
84
105
|
assert events.emoji not in events.url_unverified
|
|
85
106
|
assert events.emoji not in events.ipv6_url_unverified
|
|
@@ -193,6 +214,8 @@ async def test_events(events, helpers):
|
|
|
193
214
|
|
|
194
215
|
org_stub_1 = scan.make_event("STUB1", "ORG_STUB", parent=scan.root_event)
|
|
195
216
|
org_stub_1.scope_distance == 1
|
|
217
|
+
assert org_stub_1.netloc == None
|
|
218
|
+
assert "netloc" not in org_stub_1.json()
|
|
196
219
|
org_stub_2 = scan.make_event("STUB2", "ORG_STUB", parent=org_stub_1)
|
|
197
220
|
org_stub_2.scope_distance == 2
|
|
198
221
|
|
|
@@ -420,11 +443,17 @@ async def test_events(events, helpers):
|
|
|
420
443
|
parent_event2 = scan.make_event("evilcorp.com", parent=scan.root_event, context="test context")
|
|
421
444
|
|
|
422
445
|
event1 = scan.make_event("evilcorp.com:80", parent=parent_event1, context="test context")
|
|
446
|
+
assert hasattr(event1, "_uuid")
|
|
423
447
|
assert hasattr(event1, "uuid")
|
|
424
|
-
assert isinstance(event1.
|
|
448
|
+
assert isinstance(event1._uuid, uuid.UUID)
|
|
449
|
+
assert isinstance(event1.uuid, str)
|
|
450
|
+
assert event1.uuid == f"{event1.type}:{event1._uuid}"
|
|
425
451
|
event2 = scan.make_event("evilcorp.com:80", parent=parent_event2, context="test context")
|
|
452
|
+
assert hasattr(event2, "_uuid")
|
|
426
453
|
assert hasattr(event2, "uuid")
|
|
427
|
-
assert isinstance(event2.
|
|
454
|
+
assert isinstance(event2._uuid, uuid.UUID)
|
|
455
|
+
assert isinstance(event2.uuid, str)
|
|
456
|
+
assert event2.uuid == f"{event2.type}:{event2._uuid}"
|
|
428
457
|
# ids should match because the event type + data is the same
|
|
429
458
|
assert event1.id == event2.id
|
|
430
459
|
# but uuids should be unique!
|
|
@@ -447,7 +476,7 @@ async def test_events(events, helpers):
|
|
|
447
476
|
assert db_event.discovery_context == "test context"
|
|
448
477
|
assert db_event.discovery_path == ["test context"]
|
|
449
478
|
assert len(db_event.parent_chain) == 1
|
|
450
|
-
assert all([
|
|
479
|
+
assert all([event_uuid_regex.match(u) for u in db_event.parent_chain])
|
|
451
480
|
assert db_event.parent_chain[0] == str(db_event.uuid)
|
|
452
481
|
assert db_event.parent.uuid == scan.root_event.uuid
|
|
453
482
|
assert db_event.parent_uuid == scan.root_event.uuid
|
|
@@ -467,7 +496,7 @@ async def test_events(events, helpers):
|
|
|
467
496
|
assert json_event["parent_chain"] == db_event.parent_chain
|
|
468
497
|
assert json_event["parent_chain"][0] == str(db_event.uuid)
|
|
469
498
|
reconstituted_event = event_from_json(json_event)
|
|
470
|
-
assert isinstance(reconstituted_event.
|
|
499
|
+
assert isinstance(reconstituted_event._uuid, uuid.UUID)
|
|
471
500
|
assert str(reconstituted_event.uuid) == json_event["uuid"]
|
|
472
501
|
assert str(reconstituted_event.parent_uuid) == json_event["parent_uuid"]
|
|
473
502
|
assert reconstituted_event.uuid == db_event.uuid
|
|
@@ -94,6 +94,15 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
|
|
|
94
94
|
]
|
|
95
95
|
assert helpers.is_ip("127.0.0.1")
|
|
96
96
|
assert not helpers.is_ip("127.0.0.0.1")
|
|
97
|
+
|
|
98
|
+
assert not helpers.is_ip_type("127.0.0.1")
|
|
99
|
+
assert helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"))
|
|
100
|
+
assert not helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"), network=True)
|
|
101
|
+
assert helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"), network=False)
|
|
102
|
+
assert helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"))
|
|
103
|
+
assert helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"), network=True)
|
|
104
|
+
assert not helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"), network=False)
|
|
105
|
+
|
|
97
106
|
assert helpers.is_dns_name("evilcorp.com")
|
|
98
107
|
assert helpers.is_dns_name("evilcorp")
|
|
99
108
|
assert not helpers.is_dns_name("evilcorp", include_local=False)
|
|
@@ -212,8 +221,12 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
|
|
|
212
221
|
|
|
213
222
|
ipv4_netloc = helpers.make_netloc("192.168.1.1", 80)
|
|
214
223
|
assert ipv4_netloc == "192.168.1.1:80"
|
|
215
|
-
|
|
216
|
-
assert
|
|
224
|
+
assert helpers.make_netloc("192.168.1.1") == "192.168.1.1"
|
|
225
|
+
assert helpers.make_netloc(ipaddress.ip_address("192.168.1.1"), None) == "192.168.1.1"
|
|
226
|
+
assert helpers.make_netloc("dead::beef", "443") == "[dead::beef]:443"
|
|
227
|
+
assert helpers.make_netloc(ipaddress.ip_address("dead::beef"), 443) == "[dead::beef]:443"
|
|
228
|
+
assert helpers.make_netloc("dead::beef", None) == "[dead::beef]"
|
|
229
|
+
assert helpers.make_netloc(ipaddress.ip_address("dead::beef"), None) == "[dead::beef]"
|
|
217
230
|
|
|
218
231
|
assert helpers.get_file_extension("https://evilcorp.com/evilcorp.com/test/asdf.TXT") == "txt"
|
|
219
232
|
assert helpers.get_file_extension("/etc/conf/test.tar.gz") == "gz"
|
|
@@ -575,7 +575,7 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
|
|
|
575
575
|
},
|
|
576
576
|
)
|
|
577
577
|
|
|
578
|
-
assert len(events) ==
|
|
578
|
+
assert len(events) == 12
|
|
579
579
|
assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal == False and e.scope_distance == 0])
|
|
580
580
|
assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"])
|
|
581
581
|
assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal == False and e.scope_distance == 0])
|
|
@@ -589,9 +589,9 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
|
|
|
589
589
|
assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"])
|
|
590
590
|
assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal == False and e.scope_distance == 0])
|
|
591
591
|
assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"])
|
|
592
|
-
assert
|
|
592
|
+
assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"])
|
|
593
593
|
assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"])
|
|
594
|
-
assert
|
|
594
|
+
assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"])
|
|
595
595
|
assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal == False and e.scope_distance == 0])
|
|
596
596
|
assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"])
|
|
597
597
|
assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal == False and e.scope_distance == 0])
|
|
@@ -603,7 +603,7 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
|
|
|
603
603
|
assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"])
|
|
604
604
|
assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"])
|
|
605
605
|
|
|
606
|
-
assert len(all_events) ==
|
|
606
|
+
assert len(all_events) == 31
|
|
607
607
|
assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal == False and e.scope_distance == 0])
|
|
608
608
|
assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal == True and e.scope_distance == 0])
|
|
609
609
|
assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal == False and e.scope_distance == 0])
|
|
@@ -618,8 +618,10 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
|
|
|
618
618
|
assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal == False and e.scope_distance == 0])
|
|
619
619
|
assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal == True and e.scope_distance == 0])
|
|
620
620
|
assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal == True and e.scope_distance == 0])
|
|
621
|
+
assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal == False and e.scope_distance == 0])
|
|
621
622
|
assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal == True and e.scope_distance == 0])
|
|
622
623
|
assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal == True and e.scope_distance == 0])
|
|
624
|
+
assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal == False and e.scope_distance == 0])
|
|
623
625
|
assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal == False and e.scope_distance == 0])
|
|
624
626
|
assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal == False and e.scope_distance == 0])
|
|
625
627
|
assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal == False and e.scope_distance == 0])
|
|
@@ -660,7 +662,7 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
|
|
|
660
662
|
assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal == True and e.scope_distance == 1])
|
|
661
663
|
|
|
662
664
|
for _graph_output_events in (graph_output_events, graph_output_batch_events):
|
|
663
|
-
assert len(_graph_output_events) ==
|
|
665
|
+
assert len(_graph_output_events) == 12
|
|
664
666
|
assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal == False and e.scope_distance == 0])
|
|
665
667
|
assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"])
|
|
666
668
|
assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal == False and e.scope_distance == 0])
|
|
@@ -674,9 +676,9 @@ async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_
|
|
|
674
676
|
assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"])
|
|
675
677
|
assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"])
|
|
676
678
|
assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"])
|
|
677
|
-
assert
|
|
679
|
+
assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"])
|
|
678
680
|
assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"])
|
|
679
|
-
assert
|
|
681
|
+
assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"])
|
|
680
682
|
assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal == False and e.scope_distance == 0])
|
|
681
683
|
assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"])
|
|
682
684
|
assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal == False and e.scope_distance == 0])
|
|
@@ -380,15 +380,14 @@ async def test_modules_basic_stats(helpers, events, bbot_scanner, httpx_mock, mo
|
|
|
380
380
|
scan.modules["dummy"] = dummy(scan)
|
|
381
381
|
events = [e async for e in scan.async_start()]
|
|
382
382
|
|
|
383
|
-
assert len(events) ==
|
|
384
|
-
for e in events:
|
|
385
|
-
log.critical(e)
|
|
383
|
+
assert len(events) == 11
|
|
386
384
|
assert 2 == len([e for e in events if e.type == "SCAN"])
|
|
387
385
|
assert 4 == len([e for e in events if e.type == "DNS_NAME"])
|
|
388
386
|
# one from target and one from speculate
|
|
389
387
|
assert 2 == len([e for e in events if e.type == "DNS_NAME" and e.data == "evilcorp.com"])
|
|
390
388
|
assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.evilcorp.com"])
|
|
391
389
|
assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "asdf.evilcorp.com"])
|
|
390
|
+
assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "asdf.evilcorp.com:443"])
|
|
392
391
|
assert 1 == len([e for e in events if e.type == "ORG_STUB" and e.data == "evilcorp"])
|
|
393
392
|
assert 1 == len([e for e in events if e.type == "FINDING"])
|
|
394
393
|
assert 1 == len([e for e in events if e.type == "URL_UNVERIFIED"])
|
|
@@ -397,6 +396,7 @@ async def test_modules_basic_stats(helpers, events, bbot_scanner, httpx_mock, mo
|
|
|
397
396
|
"SCAN": 1,
|
|
398
397
|
"DNS_NAME": 4,
|
|
399
398
|
"URL": 1,
|
|
399
|
+
"OPEN_TCP_PORT": 1,
|
|
400
400
|
"ORG_STUB": 1,
|
|
401
401
|
"URL_UNVERIFIED": 1,
|
|
402
402
|
"FINDING": 1,
|
|
@@ -431,16 +431,17 @@ async def test_modules_basic_stats(helpers, events, bbot_scanner, httpx_mock, mo
|
|
|
431
431
|
assert python_stats.consumed == {
|
|
432
432
|
"DNS_NAME": 4,
|
|
433
433
|
"FINDING": 1,
|
|
434
|
+
"OPEN_TCP_PORT": 1,
|
|
434
435
|
"ORG_STUB": 1,
|
|
435
436
|
"SCAN": 1,
|
|
436
437
|
"URL": 1,
|
|
437
438
|
"URL_UNVERIFIED": 1,
|
|
438
439
|
}
|
|
439
|
-
assert python_stats.consumed_total ==
|
|
440
|
+
assert python_stats.consumed_total == 10
|
|
440
441
|
|
|
441
442
|
speculate_stats = scan.stats.module_stats["speculate"]
|
|
442
|
-
assert speculate_stats.produced == {"DNS_NAME": 1, "URL_UNVERIFIED": 1, "ORG_STUB": 1}
|
|
443
|
-
assert speculate_stats.produced_total ==
|
|
443
|
+
assert speculate_stats.produced == {"DNS_NAME": 1, "URL_UNVERIFIED": 1, "ORG_STUB": 1, "OPEN_TCP_PORT": 1}
|
|
444
|
+
assert speculate_stats.produced_total == 4
|
|
444
445
|
assert speculate_stats.consumed == {"URL": 1, "DNS_NAME": 3, "URL_UNVERIFIED": 1, "IP_ADDRESS": 3}
|
|
445
446
|
assert speculate_stats.consumed_total == 8
|
|
446
447
|
|
|
@@ -169,6 +169,11 @@ exclude_flags:
|
|
|
169
169
|
|
|
170
170
|
def test_preset_scope():
|
|
171
171
|
|
|
172
|
+
# test target merging
|
|
173
|
+
scan = Scanner("1.2.3.4", preset=Preset.from_dict({"target": ["evilcorp.com"]}))
|
|
174
|
+
assert set([str(h) for h in scan.preset.target.seeds.hosts]) == {"1.2.3.4", "evilcorp.com"}
|
|
175
|
+
assert set([e.data for e in scan.target]) == {"1.2.3.4", "evilcorp.com"}
|
|
176
|
+
|
|
172
177
|
blank_preset = Preset()
|
|
173
178
|
blank_preset = blank_preset.bake()
|
|
174
179
|
assert not blank_preset.target
|
|
@@ -527,9 +532,22 @@ def test_preset_module_resolution(clean_default_config):
|
|
|
527
532
|
assert set(preset.scan_modules) == {"wayback"}
|
|
528
533
|
|
|
529
534
|
# modules + module exclusions
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
assert
|
|
535
|
+
preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "wappalyzer", "wayback"]).bake()
|
|
536
|
+
baked_preset = preset.bake()
|
|
537
|
+
assert baked_preset.modules == {
|
|
538
|
+
"wayback",
|
|
539
|
+
"cloudcheck",
|
|
540
|
+
"python",
|
|
541
|
+
"json",
|
|
542
|
+
"speculate",
|
|
543
|
+
"dnsresolve",
|
|
544
|
+
"aggregate",
|
|
545
|
+
"excavate",
|
|
546
|
+
"txt",
|
|
547
|
+
"httpx",
|
|
548
|
+
"csv",
|
|
549
|
+
"wappalyzer",
|
|
550
|
+
}
|
|
533
551
|
|
|
534
552
|
|
|
535
553
|
@pytest.mark.asyncio
|
|
@@ -9,13 +9,32 @@ class TestShodan_DNS(ModuleTestBase):
|
|
|
9
9
|
url="https://api.shodan.io/api-info?key=asdf",
|
|
10
10
|
)
|
|
11
11
|
module_test.httpx_mock.add_response(
|
|
12
|
-
url="https://api.shodan.io/dns/domain/blacklanternsecurity.com?key=asdf",
|
|
12
|
+
url="https://api.shodan.io/dns/domain/blacklanternsecurity.com?key=asdf&page=1",
|
|
13
13
|
json={
|
|
14
14
|
"subdomains": [
|
|
15
15
|
"asdf",
|
|
16
16
|
],
|
|
17
17
|
},
|
|
18
18
|
)
|
|
19
|
+
module_test.httpx_mock.add_response(
|
|
20
|
+
url="https://api.shodan.io/dns/domain/blacklanternsecurity.com?key=asdf&page=2",
|
|
21
|
+
json={
|
|
22
|
+
"subdomains": [
|
|
23
|
+
"www",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
)
|
|
27
|
+
await module_test.mock_dns(
|
|
28
|
+
{
|
|
29
|
+
"blacklanternsecurity.com": {
|
|
30
|
+
"A": ["127.0.0.11"],
|
|
31
|
+
},
|
|
32
|
+
"www.blacklanternsecurity.com": {"A": ["127.0.0.22"]},
|
|
33
|
+
"asdf.blacklanternsecurity.com": {"A": ["127.0.0.33"]},
|
|
34
|
+
}
|
|
35
|
+
)
|
|
19
36
|
|
|
20
37
|
def check(self, module_test, events):
|
|
38
|
+
assert len([e for e in events if e.type == "DNS_NAME"]) == 3, "Failed to detect both subdomains"
|
|
21
39
|
assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain"
|
|
40
|
+
assert any(e.data == "www.blacklanternsecurity.com" for e in events), "Failed to detect subdomain"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
bbot/__init__.py,sha256=
|
|
1
|
+
bbot/__init__.py,sha256=uGNlVZLVuhzc5H4GbnGYmOTRrPsfNQvnztWI-cJlTjE,130
|
|
2
2
|
bbot/cli.py,sha256=7S3a4eB-Dl8yodc5WC-927Z30CNlLl9EXimGvIVypJo,10434
|
|
3
3
|
bbot/core/__init__.py,sha256=l255GJE_DvUnWvrRb0J5lG-iMztJ8zVvoweDOfegGtI,46
|
|
4
4
|
bbot/core/config/__init__.py,sha256=zYNw2Me6tsEr8hOOkLb4BQ97GB7Kis2k--G81S8vofU,342
|
|
@@ -7,7 +7,7 @@ bbot/core/config/logger.py,sha256=C9txmKQtqSFnWU1AapwFS9cZgDBtNZQh4io_13d3AxA,95
|
|
|
7
7
|
bbot/core/core.py,sha256=twd7-fiaaxzgcWTPwT1zbSWfAa_gHHfl7gAFvLYvFYg,6358
|
|
8
8
|
bbot/core/engine.py,sha256=wGopKa2GNs61r16Pr_xtp6Si9AT6I-lE83iWhEgtxwA,29290
|
|
9
9
|
bbot/core/event/__init__.py,sha256=8ut88ZUg0kbtWkOx2j3XzNr_3kTfgoM-3UdiWHFA_ag,56
|
|
10
|
-
bbot/core/event/base.py,sha256=
|
|
10
|
+
bbot/core/event/base.py,sha256=YHWevdDo5sHIIMKz_9TkWFYGTVtoD3fv957TpMO-6DQ,59498
|
|
11
11
|
bbot/core/event/helpers.py,sha256=PUN4Trq5_wpKVuhmwUQWAr40apgMXhJ9Gz-VfZ0j3lA,1554
|
|
12
12
|
bbot/core/flags.py,sha256=Ltvm8Bc4D65I55HuU5bzyjO1R3yMDNpVmreGU83ZBXE,1266
|
|
13
13
|
bbot/core/helpers/__init__.py,sha256=0UNwcZjNsX41hbHdo3yZPuARkYWch-okI68DScexve4,86
|
|
@@ -28,13 +28,13 @@ bbot/core/helpers/dns/mock.py,sha256=Ztkp2aOuwDJ0NTQSlAk2H0s3Stx9wIM22Qm3VtqWMKM
|
|
|
28
28
|
bbot/core/helpers/files.py,sha256=GqrwNGJljUvGSzaOW5-Y357hkt7j88dOYbzQxJGsdTc,5787
|
|
29
29
|
bbot/core/helpers/helper.py,sha256=3O96peNBvSkaJosft8w9-nKjCscEdykTayGcUlHRqLw,8394
|
|
30
30
|
bbot/core/helpers/interactsh.py,sha256=Q9IHUzH-T7e1s4YTHevHe-VJj1Mokv0EHY16UZJdl8M,12627
|
|
31
|
-
bbot/core/helpers/misc.py,sha256=
|
|
31
|
+
bbot/core/helpers/misc.py,sha256=rvfZmm8UHCChmbMorjPMybaCZTkERrKZhxvY9S4dVPc,86873
|
|
32
32
|
bbot/core/helpers/names_generator.py,sha256=Sj_Q-7KQyElEpalzlUadSwaniESqrIVVEle9ycPIiho,10322
|
|
33
33
|
bbot/core/helpers/ntlm.py,sha256=P2Xj4-GPos2iAzw4dfk0FJp6oGyycGhu2x6sLDVjYjs,2573
|
|
34
34
|
bbot/core/helpers/process.py,sha256=6D9_LYZrhQ0Jb7Rn58rWMafmAZn7rVVA2LqMKwpR_xg,2271
|
|
35
35
|
bbot/core/helpers/ratelimiter.py,sha256=K8qFIyJPJtfdb9kSW6_lL6ahWqxR2uWyCBkDlg6uJgo,1990
|
|
36
36
|
bbot/core/helpers/regex.py,sha256=XURaY6ijpOYYU9lzWMAKg12G1VFtGJjlJl07_eN1xxk,4170
|
|
37
|
-
bbot/core/helpers/regexes.py,sha256=
|
|
37
|
+
bbot/core/helpers/regexes.py,sha256=kz3y3hyEJvsnF7-4NrkrHTwwhkbRqEYi_wqA_rmZlgQ,5859
|
|
38
38
|
bbot/core/helpers/url.py,sha256=1NDrvirODzzD6Mcssu-4WDNerMeMdekHCFzhRCS0m3g,5947
|
|
39
39
|
bbot/core/helpers/validators.py,sha256=cglRDybXiFDh2vKwqjqv7Ruu1TWmSzPcbuQ3Rvky5JU,9696
|
|
40
40
|
bbot/core/helpers/web/__init__.py,sha256=pIEkL3DhjaGTSmZ7D3yKKYwWpntoLRILekV2wWsbsws,27
|
|
@@ -58,7 +58,7 @@ bbot/modules/baddns.py,sha256=FFGpJ0AdcpYBh_i8VMYOUj6C_PhzkFls263DoVmUXGY,6376
|
|
|
58
58
|
bbot/modules/baddns_direct.py,sha256=_Z_snPDU5VqF3jb2CAoX5Sb94GnhYVP22JIK5TdpF_Y,3820
|
|
59
59
|
bbot/modules/baddns_zone.py,sha256=bTpYzQYLt4ZJo_Jan5K4NsYL7O1PMVQvJHmYPy6QyvY,1035
|
|
60
60
|
bbot/modules/badsecrets.py,sha256=WMeIhjafD63sXShYGtbAk2kw12PgxMIZh8EMbYg7x20,5108
|
|
61
|
-
bbot/modules/base.py,sha256
|
|
61
|
+
bbot/modules/base.py,sha256=-nPgoPjMwcveZ81fzb4TwhbtBFqNYorj-zD3TG91ZPg,71115
|
|
62
62
|
bbot/modules/bevigil.py,sha256=EFA4N_aJDF20KjrzbzdkHaTL1GfOF6ohBMlNIEJne6s,2850
|
|
63
63
|
bbot/modules/binaryedge.py,sha256=W6VMbV7-tVAduUNbcmS6uLLJixb3sDJmqC9m4IGB6Yg,1391
|
|
64
64
|
bbot/modules/bucket_amazon.py,sha256=mwjYeEAcdfOpjbOa1sD8U9KBMMVY_c8FoHjSGR9GQbg,730
|
|
@@ -96,7 +96,7 @@ bbot/modules/ffuf_shortnames.py,sha256=9Kh0kJsw7XXpXmCkiB5eAhG4h9rSo8Y-mB3p0EDa_
|
|
|
96
96
|
bbot/modules/filedownload.py,sha256=1prC84wAQO-W1HstitKPQ0-eYEApjzFn3RHFa9oaqLc,8185
|
|
97
97
|
bbot/modules/fingerprintx.py,sha256=rdlR9d64AntAhbS_eJzh8bZCeLPTJPSKdkdKdhH_qAo,3269
|
|
98
98
|
bbot/modules/fullhunt.py,sha256=R70VpNZezUOeCOuYiYaG3oJCIOjOjB6lMPaVJ-xPVr0,1305
|
|
99
|
-
bbot/modules/generic_ssrf.py,sha256=
|
|
99
|
+
bbot/modules/generic_ssrf.py,sha256=FZ7XZ2RbBk5PVwa7wHasSkEsatUFWvCH70ZvPbg-EQA,7946
|
|
100
100
|
bbot/modules/git.py,sha256=CMDarsmBemZEzZSeQTzB70XD8IRdwdG39zXpwDdgZbw,1383
|
|
101
101
|
bbot/modules/git_clone.py,sha256=XFZXx0k97EMY3E5PZzdNvqQzZddOfRMaVp5ol2gk11s,2468
|
|
102
102
|
bbot/modules/github_codesearch.py,sha256=VbzSsnJKL1SWSl6rB88qWl26bAgszM7Gbo4HCOl6XUU,3540
|
|
@@ -115,9 +115,9 @@ bbot/modules/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
|
115
115
|
bbot/modules/internal/aggregate.py,sha256=csWYIt2fUp9K_CRxP3bndUMIjpNIh8rmBubp5Fr1-nc,395
|
|
116
116
|
bbot/modules/internal/base.py,sha256=BXO4Hc7XKaAOaLzolF3krJX1KibPxtek2GTQUgnCHk0,387
|
|
117
117
|
bbot/modules/internal/cloudcheck.py,sha256=kkD5DC5Y7EPCiVTdEspZktkflArU3unx--9ciBikxHo,4099
|
|
118
|
-
bbot/modules/internal/dnsresolve.py,sha256=
|
|
119
|
-
bbot/modules/internal/excavate.py,sha256=
|
|
120
|
-
bbot/modules/internal/speculate.py,sha256=
|
|
118
|
+
bbot/modules/internal/dnsresolve.py,sha256=rmXBb6r8MNYrHlnTbES1ok5M9q3JD3Oj6AOx6d0Bawc,14558
|
|
119
|
+
bbot/modules/internal/excavate.py,sha256=1kPiaUlpJVT_xgPgmzqhpf04uanIe9ZayQsWANbzhd4,51238
|
|
120
|
+
bbot/modules/internal/speculate.py,sha256=wP75lpdnxhoGiARmSdIlvPyYHQKx1Tu6oCu7_sKV9Qs,9850
|
|
121
121
|
bbot/modules/internetdb.py,sha256=Edg0Z84dH8dPTZMd7RlzvYBYNq8JHs_ns_ldnFxwRKo,5415
|
|
122
122
|
bbot/modules/ip2location.py,sha256=yGivX9fzvwvLpnqmYCP2a8SPjTarzrZxfRluog-nkME,2628
|
|
123
123
|
bbot/modules/ipneighbor.py,sha256=Gr-HGtyZRDp_fPjpw-Mq1al7ocFdiZbKsAoAit-EUlA,1591
|
|
@@ -162,7 +162,7 @@ bbot/modules/robots.py,sha256=G2_IvLcI24iMXJxii44H1z6m5KWe2NMIDtVMbQGaXDE,2172
|
|
|
162
162
|
bbot/modules/secretsdb.py,sha256=MA6IKo5rOvC0Dzt-F4QVrSwLkcPRwWLd9FpzqYkc8u8,3082
|
|
163
163
|
bbot/modules/securitytrails.py,sha256=j2ZcY_qO48mQquWwS3FOaHgZiomr2ETMGv28y5qtRZM,1088
|
|
164
164
|
bbot/modules/securitytxt.py,sha256=-GuIelHW04256VlcgfyV4ylfo7oSbAwToxtV2Cfo2p0,4558
|
|
165
|
-
bbot/modules/shodan_dns.py,sha256=
|
|
165
|
+
bbot/modules/shodan_dns.py,sha256=PJaeqGlTfhQfKgc_3fDmC4mLWsOb4BnRUpVD_h3Y8cU,836
|
|
166
166
|
bbot/modules/sitedossier.py,sha256=0GOGMt0x3wro2FvP4ngNa2lcTmcjjq5x1SM8l5HG8Cs,2283
|
|
167
167
|
bbot/modules/skymem.py,sha256=NApG68Eh22jMcV1H590SXvQIlLJY4JOfGUeNaOJaMKs,1928
|
|
168
168
|
bbot/modules/smuggler.py,sha256=v8NCRgzd7wpEFZJUTAArG04bN8nNTGiHxYpGBapzi14,1580
|
|
@@ -175,15 +175,15 @@ bbot/modules/templates/bucket.py,sha256=x-c_iAeMILux6wRm0xkUUJkc2P69hYWS6DxqD7g5
|
|
|
175
175
|
bbot/modules/templates/github.py,sha256=ENnDWpzzmZBsTisDx6Cg9V_NwJKyVyPIOpGAPktigdI,1455
|
|
176
176
|
bbot/modules/templates/postman.py,sha256=oxwVusW2EdNotVX7xnnxCTnWtj3xNPbfs8aff9s4phs,614
|
|
177
177
|
bbot/modules/templates/shodan.py,sha256=BfI0mNPbqkykGmjMtARhmCGKmk1uq7yTlZoPgzzJ040,1175
|
|
178
|
-
bbot/modules/templates/subdomain_enum.py,sha256=
|
|
178
|
+
bbot/modules/templates/subdomain_enum.py,sha256=lT5MZF66OuzsyFFrj20wKlsZflzL9MOkPjDIbN3o65o,8375
|
|
179
179
|
bbot/modules/templates/webhook.py,sha256=MYhKWrNYrsfM0a4PR6yVotudLyyCwgmy2eI-l9LvpBs,3706
|
|
180
|
-
bbot/modules/trickest.py,sha256=
|
|
180
|
+
bbot/modules/trickest.py,sha256=HfAzjnawxXd9ypi3gumDHqImE5-C7uwNugo8d_b9HT0,1544
|
|
181
181
|
bbot/modules/trufflehog.py,sha256=KMFYbjKEyoNaJDoID0SoDvbCRPaDwalMD6H2lQaI1QE,8555
|
|
182
182
|
bbot/modules/unstructured.py,sha256=si3_Y__A36QOBdkIUocVXCHrmUqM0E-JSnoOeRpELYE,5311
|
|
183
183
|
bbot/modules/url_manipulation.py,sha256=BI-OhlzNzP5xvwzHphL4qdehc4NiEYnL2BNK-JoEm90,4322
|
|
184
184
|
bbot/modules/urlscan.py,sha256=ajhiX2sj-zZDlKU1q5rE8JTzxioj1mDLqZ9PRSQCpAw,3741
|
|
185
185
|
bbot/modules/viewdns.py,sha256=f0vwoLpua2Ovw1gcrjoafUdaAP9fi4bHgTUiDOe8iWg,2596
|
|
186
|
-
bbot/modules/virustotal.py,sha256=
|
|
186
|
+
bbot/modules/virustotal.py,sha256=GsGaVF05IMgSNOQtUx1B8UXL5JA1Bt8M6ZDWJiiEQ1k,1213
|
|
187
187
|
bbot/modules/wafw00f.py,sha256=I-jEnHWxO4Ga72ukdeBlTGJB9xeucCT3lpDhhFaVyAk,2536
|
|
188
188
|
bbot/modules/wappalyzer.py,sha256=LL5QeY5DeG7LdaFzZZU-LXaVlJ-sHzOwQLgFtxW3TNg,2176
|
|
189
189
|
bbot/modules/wayback.py,sha256=9cxd_HfHgLp4AChzA8C0Zjd6DIJ7c3NsJ02W2oLIXuU,3257
|
|
@@ -212,8 +212,8 @@ bbot/scanner/preset/args.py,sha256=9Nmir2dHJWzN66m6N-mA0QEKiOgt8vWq23O8BG50eMA,1
|
|
|
212
212
|
bbot/scanner/preset/conditions.py,sha256=hFL9cSIWGEsv2TfM5UGurf0c91cyaM8egb5IngBmIjA,1569
|
|
213
213
|
bbot/scanner/preset/environ.py,sha256=-wbFk1YHpU8IJLKVw23Q3btQTICeX0iulURo7D673L0,4732
|
|
214
214
|
bbot/scanner/preset/path.py,sha256=p9tZC7XcgZv2jXpbEJAg1lU2b4ZLX5COFnCxEUOXz2g,2234
|
|
215
|
-
bbot/scanner/preset/preset.py,sha256=
|
|
216
|
-
bbot/scanner/scanner.py,sha256=
|
|
215
|
+
bbot/scanner/preset/preset.py,sha256=7q6PB9LalIzHyb4eiMDVKE6CapWBCKVw7350M0fSiwM,40083
|
|
216
|
+
bbot/scanner/scanner.py,sha256=62DKCjgV1uLxNAwpxjvE5h1uzQCxG-nzBxp1PBCSVKc,53674
|
|
217
217
|
bbot/scanner/stats.py,sha256=re93sArKXZSiD0Owgqk2J3Kdvfm3RL4Y9Qy_VOcaVk8,3623
|
|
218
218
|
bbot/scanner/target.py,sha256=X25gpgRv5HmqQjGADiSe6b8744yOkRhAGAvKKYbXnSI,19886
|
|
219
219
|
bbot/scripts/docs.py,sha256=kg2CzovmUVGJx9hBZjAjUdE1hXeIwC7Ry3CyrnE8GL8,10782
|
|
@@ -228,20 +228,20 @@ bbot/test/test_output.ndjson,sha256=Jfor8nUJ3QTEwXxD6UULrFXM4zhP5wflWo_UNekM3V8,
|
|
|
228
228
|
bbot/test/test_step_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
229
229
|
bbot/test/test_step_1/test__module__tests.py,sha256=RpD4yuVuQRgbbUkfuasxUlyoVxhTm6TeDyi87y_AaK0,1461
|
|
230
230
|
bbot/test/test_step_1/test_bloom_filter.py,sha256=OpiZXsBX-I8QdTK0LqSYkGMDLA6vL_6t0wco9ypxxtQ,2114
|
|
231
|
-
bbot/test/test_step_1/test_cli.py,sha256=
|
|
231
|
+
bbot/test/test_step_1/test_cli.py,sha256=m4LyIiiedR41f5SpnlkxgE-f42fF7qoGcuthpYxQ_m8,24688
|
|
232
232
|
bbot/test/test_step_1/test_command.py,sha256=5IeGV6TKB0xtFEsfsU_0mNrOmEdIQiQ3FHkUmsBNoOI,6485
|
|
233
233
|
bbot/test/test_step_1/test_config.py,sha256=Q38hygpke2GDcv8OguVZuiSOnfDJxEMrRy20dN5Qsn0,887
|
|
234
234
|
bbot/test/test_step_1/test_depsinstaller.py,sha256=zr9f-wJDotD1ZvKXGEuDRWzFYMAYBI6209mI_PWPtTQ,703
|
|
235
235
|
bbot/test/test_step_1/test_dns.py,sha256=YZtSbja-Z76KC9MWBieRExolVWHm0WqssL0WHUpUiC8,30932
|
|
236
236
|
bbot/test/test_step_1/test_docs.py,sha256=YWVGNRfzcrvDmFekX0Cq9gutQplsqvhKTpZ0XK4tWvo,82
|
|
237
237
|
bbot/test/test_step_1/test_engine.py,sha256=Bfid3-D9ziN93w4vym97tFEn_l2Iof08wjITTv_lAZw,4269
|
|
238
|
-
bbot/test/test_step_1/test_events.py,sha256
|
|
238
|
+
bbot/test/test_step_1/test_events.py,sha256=D9W3zGxRWUIm0SYklsWRE3IeAPcMdWLAOIMWkI24Rpc,45130
|
|
239
239
|
bbot/test/test_step_1/test_files.py,sha256=5Q_3jPpMXULxDHsanSDUaj8zF8bXzKdiJZHOmoYpLhQ,699
|
|
240
|
-
bbot/test/test_step_1/test_helpers.py,sha256=
|
|
240
|
+
bbot/test/test_step_1/test_helpers.py,sha256=oY2hWhgL-TCB67ve1bAyIwZO3wNRWpx4SjCHNUxHep8,38676
|
|
241
241
|
bbot/test/test_step_1/test_manager_deduplication.py,sha256=hZQpDXzg6zvzxFolVOcJuY-ME8NXjZUsqS70BRNXp8A,15594
|
|
242
|
-
bbot/test/test_step_1/test_manager_scope_accuracy.py,sha256=
|
|
243
|
-
bbot/test/test_step_1/test_modules_basic.py,sha256=
|
|
244
|
-
bbot/test/test_step_1/test_presets.py,sha256=
|
|
242
|
+
bbot/test/test_step_1/test_manager_scope_accuracy.py,sha256=_4O5bW9PA2DIeguvqzb4CMm0i1joqqBBppw7qElL2a0,79767
|
|
243
|
+
bbot/test/test_step_1/test_modules_basic.py,sha256=h4eCe-UhniwXZGhTEa6tH-RGeBF8tyjpSHAPsSu-ssw,20295
|
|
244
|
+
bbot/test/test_step_1/test_presets.py,sha256=RXdRCGBgwLBJk_npn5Pyph3IhLTfy0ULkb4v_aZjABA,37299
|
|
245
245
|
bbot/test/test_step_1/test_python_api.py,sha256=BYIVREUy7rd7tKfUsnIX-w_eqQDTEo5UplMZeGMb4bs,5317
|
|
246
246
|
bbot/test/test_step_1/test_regexes.py,sha256=btlDgwM5crSkXFZNydLYn8lCDmyLW_8oX_6Aos5xAHk,14376
|
|
247
247
|
bbot/test/test_step_1/test_scan.py,sha256=yLQAZ5tvIwTULBGgUmXVg8KwMmujal7kB2p-S2_ORzA,5461
|
|
@@ -348,7 +348,7 @@ bbot/test/test_step_2/module_tests/test_module_robots.py,sha256=8rRw4GpGE6tN_W3o
|
|
|
348
348
|
bbot/test/test_step_2/module_tests/test_module_secretsdb.py,sha256=EmqWGnqAQHGEZxbmJJXHwIgz5SQi4R3Fq982k6sYkZM,537
|
|
349
349
|
bbot/test/test_step_2/module_tests/test_module_securitytrails.py,sha256=NB8_PhWN1-2s8wporRjI6rrQeQW4inoz4Z_mBhhycXo,758
|
|
350
350
|
bbot/test/test_step_2/module_tests/test_module_securitytxt.py,sha256=i9Emp1utut1LPIe502Jb3XzN4GiVBeo4ATLFR9w4rbY,2382
|
|
351
|
-
bbot/test/test_step_2/module_tests/test_module_shodan_dns.py,sha256=
|
|
351
|
+
bbot/test/test_step_2/module_tests/test_module_shodan_dns.py,sha256=9DpFizZguP2aFCKI1HgXzxy3sB_afA03pzIx0BDfgqg,1515
|
|
352
352
|
bbot/test/test_step_2/module_tests/test_module_sitedossier.py,sha256=YAaTzCL-lOYFu-42zk4dsV33V3Da3Md6rcAuBy9jgeY,6584
|
|
353
353
|
bbot/test/test_step_2/module_tests/test_module_skymem.py,sha256=VaRhEmrZ0auKmxExeuYmzryXpZ0h78AqSVozkqJ5dXo,2321
|
|
354
354
|
bbot/test/test_step_2/module_tests/test_module_slack.py,sha256=oJvUzSowPAhpbMFnzl-iS3XvLQBxCaO_vofhu_bgR4w,317
|
|
@@ -393,8 +393,8 @@ bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt,sha256=ruUQwVfia1_m2u
|
|
|
393
393
|
bbot/wordlists/top_open_ports_nmap.txt,sha256=LmdFYkfapSxn1pVuQC2LkOIY2hMLgG-Xts7DVtYzweM,42727
|
|
394
394
|
bbot/wordlists/valid_url_schemes.txt,sha256=VciB-ww0y-O8Ii1wpTR6rJzGDiC2r-dhVsIJApS1ZYU,3309
|
|
395
395
|
bbot/wordlists/wordninja_dns.txt.gz,sha256=DYHvvfW0TvzrVwyprqODAk4tGOxv5ezNmCPSdPuDUnQ,570241
|
|
396
|
-
bbot-2.1.0.
|
|
397
|
-
bbot-2.1.0.
|
|
398
|
-
bbot-2.1.0.
|
|
399
|
-
bbot-2.1.0.
|
|
400
|
-
bbot-2.1.0.
|
|
396
|
+
bbot-2.1.0.5028rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
|
|
397
|
+
bbot-2.1.0.5028rc0.dist-info/METADATA,sha256=3Y7ocHDJJpm5Ebb7PhjejhASPdJO6tK52qlUo_6RUQI,16930
|
|
398
|
+
bbot-2.1.0.5028rc0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
399
|
+
bbot-2.1.0.5028rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
|
|
400
|
+
bbot-2.1.0.5028rc0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|