bbot 2.2.0.5263rc0__py3-none-any.whl → 2.2.0.5309rc0__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 +1 -1
- bbot/cli.py +1 -1
- bbot/core/engine.py +2 -2
- bbot/core/event/base.py +23 -2
- bbot/core/helpers/bloom.py +8 -1
- bbot/core/helpers/depsinstaller/installer.py +8 -5
- bbot/core/helpers/dns/helpers.py +2 -2
- bbot/core/helpers/helper.py +4 -3
- bbot/core/helpers/misc.py +29 -5
- bbot/core/helpers/regexes.py +2 -1
- bbot/core/helpers/web/web.py +1 -1
- bbot/defaults.yml +3 -0
- bbot/modules/anubisdb.py +1 -1
- bbot/modules/baddns.py +1 -1
- bbot/modules/bevigil.py +2 -2
- bbot/modules/binaryedge.py +1 -1
- bbot/modules/bufferoverrun.py +2 -3
- bbot/modules/builtwith.py +2 -2
- bbot/modules/c99.py +4 -2
- bbot/modules/certspotter.py +4 -2
- bbot/modules/chaos.py +4 -2
- bbot/modules/columbus.py +1 -1
- bbot/modules/crt.py +4 -2
- bbot/modules/digitorus.py +1 -1
- bbot/modules/dnscaa.py +3 -3
- bbot/modules/fullhunt.py +1 -1
- bbot/modules/hackertarget.py +4 -2
- bbot/modules/internal/excavate.py +2 -3
- bbot/modules/internal/speculate.py +34 -24
- bbot/modules/leakix.py +6 -5
- bbot/modules/myssl.py +1 -1
- bbot/modules/otx.py +4 -2
- bbot/modules/passivetotal.py +4 -2
- bbot/modules/rapiddns.py +2 -7
- bbot/modules/securitytrails.py +4 -2
- bbot/modules/shodan_dns.py +1 -1
- bbot/modules/subdomaincenter.py +1 -1
- bbot/modules/templates/subdomain_enum.py +3 -3
- bbot/modules/trickest.py +1 -1
- bbot/modules/virustotal.py +2 -7
- bbot/modules/zoomeye.py +5 -3
- bbot/presets/fast.yml +16 -0
- bbot/presets/spider.yml +4 -0
- bbot/scanner/manager.py +1 -2
- bbot/scanner/preset/args.py +20 -4
- bbot/scanner/preset/path.py +3 -1
- bbot/scanner/preset/preset.py +18 -12
- bbot/scanner/scanner.py +7 -2
- bbot/scanner/target.py +236 -434
- bbot/test/bbot_fixtures.py +5 -2
- bbot/test/conftest.py +95 -83
- bbot/test/test_step_1/test_bloom_filter.py +2 -0
- bbot/test/test_step_1/test_cli.py +36 -0
- bbot/test/test_step_1/test_dns.py +2 -1
- bbot/test/test_step_1/test_events.py +16 -3
- bbot/test/test_step_1/test_helpers.py +17 -0
- bbot/test/test_step_1/test_modules_basic.py +0 -3
- bbot/test/test_step_1/test_presets.py +51 -38
- bbot/test/test_step_1/test_python_api.py +4 -0
- bbot/test/test_step_1/test_scan.py +8 -2
- bbot/test/test_step_1/test_target.py +227 -129
- bbot/test/test_step_1/test_web.py +3 -0
- bbot/test/test_step_2/module_tests/test_module_dastardly.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +0 -6
- bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_leakix.py +5 -1
- {bbot-2.2.0.5263rc0.dist-info → bbot-2.2.0.5309rc0.dist-info}/METADATA +4 -4
- {bbot-2.2.0.5263rc0.dist-info → bbot-2.2.0.5309rc0.dist-info}/RECORD +71 -70
- {bbot-2.2.0.5263rc0.dist-info → bbot-2.2.0.5309rc0.dist-info}/LICENSE +0 -0
- {bbot-2.2.0.5263rc0.dist-info → bbot-2.2.0.5309rc0.dist-info}/WHEEL +0 -0
- {bbot-2.2.0.5263rc0.dist-info → bbot-2.2.0.5309rc0.dist-info}/entry_points.txt +0 -0
bbot/modules/myssl.py
CHANGED
|
@@ -17,7 +17,7 @@ class myssl(subdomain_enum):
|
|
|
17
17
|
url = f"{self.base_url}?domain={self.helpers.quote(query)}"
|
|
18
18
|
return await self.api_request(url)
|
|
19
19
|
|
|
20
|
-
def parse_results(self, r, query):
|
|
20
|
+
async def parse_results(self, r, query):
|
|
21
21
|
results = set()
|
|
22
22
|
json = r.json()
|
|
23
23
|
if json and isinstance(json, dict):
|
bbot/modules/otx.py
CHANGED
|
@@ -17,10 +17,12 @@ class otx(subdomain_enum):
|
|
|
17
17
|
url = f"{self.base_url}/api/v1/indicators/domain/{self.helpers.quote(query)}/passive_dns"
|
|
18
18
|
return self.api_request(url)
|
|
19
19
|
|
|
20
|
-
def parse_results(self, r, query):
|
|
20
|
+
async def parse_results(self, r, query):
|
|
21
|
+
results = set()
|
|
21
22
|
j = r.json()
|
|
22
23
|
if isinstance(j, dict):
|
|
23
24
|
for entry in j.get("passive_dns", []):
|
|
24
25
|
subdomain = entry.get("hostname", "")
|
|
25
26
|
if subdomain:
|
|
26
|
-
|
|
27
|
+
results.add(subdomain)
|
|
28
|
+
return results
|
bbot/modules/passivetotal.py
CHANGED
|
@@ -39,6 +39,8 @@ class passivetotal(subdomain_enum_apikey):
|
|
|
39
39
|
url = f"{self.base_url}/enrichment/subdomains?query={self.helpers.quote(query)}"
|
|
40
40
|
return await self.api_request(url)
|
|
41
41
|
|
|
42
|
-
def parse_results(self, r, query):
|
|
42
|
+
async def parse_results(self, r, query):
|
|
43
|
+
results = set()
|
|
43
44
|
for subdomain in r.json().get("subdomains", []):
|
|
44
|
-
|
|
45
|
+
results.add(f"{subdomain}.{query}")
|
|
46
|
+
return results
|
bbot/modules/rapiddns.py
CHANGED
|
@@ -18,11 +18,6 @@ class rapiddns(subdomain_enum):
|
|
|
18
18
|
response = await self.api_request(url, timeout=self.http_timeout + 10)
|
|
19
19
|
return response
|
|
20
20
|
|
|
21
|
-
def parse_results(self, r, query):
|
|
22
|
-
results = set()
|
|
21
|
+
async def parse_results(self, r, query):
|
|
23
22
|
text = getattr(r, "text", "")
|
|
24
|
-
|
|
25
|
-
match = match.lower()
|
|
26
|
-
if match.endswith(query):
|
|
27
|
-
results.add(match)
|
|
28
|
-
return results
|
|
23
|
+
return await self.scan.extract_in_scope_hostnames(text)
|
bbot/modules/securitytrails.py
CHANGED
|
@@ -26,8 +26,10 @@ class securitytrails(subdomain_enum_apikey):
|
|
|
26
26
|
response = await self.api_request(url)
|
|
27
27
|
return response
|
|
28
28
|
|
|
29
|
-
def parse_results(self, r, query):
|
|
29
|
+
async def parse_results(self, r, query):
|
|
30
|
+
results = set()
|
|
30
31
|
j = r.json()
|
|
31
32
|
if isinstance(j, dict):
|
|
32
33
|
for host in j.get("subdomains", []):
|
|
33
|
-
|
|
34
|
+
results.add(f"{host}.{query}")
|
|
35
|
+
return results
|
bbot/modules/shodan_dns.py
CHANGED
|
@@ -22,5 +22,5 @@ class shodan_dns(shodan):
|
|
|
22
22
|
def make_url(self, query):
|
|
23
23
|
return f"{self.base_url}/dns/domain/{self.helpers.quote(query)}?key={{api_key}}&page={{page}}"
|
|
24
24
|
|
|
25
|
-
def parse_results(self, json, query):
|
|
25
|
+
async def parse_results(self, json, query):
|
|
26
26
|
return [f"{sub}.{query}" for sub in json.get("subdomains", [])]
|
bbot/modules/subdomaincenter.py
CHANGED
|
@@ -106,7 +106,7 @@ class subdomain_enum(BaseModule):
|
|
|
106
106
|
break
|
|
107
107
|
return ".".join([s for s in query.split(".") if s != "_wildcard"])
|
|
108
108
|
|
|
109
|
-
def parse_results(self, r, query=None):
|
|
109
|
+
async def parse_results(self, r, query=None):
|
|
110
110
|
json = r.json()
|
|
111
111
|
if json:
|
|
112
112
|
for hostname in json:
|
|
@@ -123,7 +123,7 @@ class subdomain_enum(BaseModule):
|
|
|
123
123
|
self.info(f'Query "{query}" failed (no response)')
|
|
124
124
|
return []
|
|
125
125
|
try:
|
|
126
|
-
results = list(parse_fn(response, query))
|
|
126
|
+
results = list(await parse_fn(response, query))
|
|
127
127
|
except Exception as e:
|
|
128
128
|
if response:
|
|
129
129
|
self.info(
|
|
@@ -144,7 +144,7 @@ class subdomain_enum(BaseModule):
|
|
|
144
144
|
agen = self.api_page_iter(url, page_size=self.page_size, **self.api_page_iter_kwargs)
|
|
145
145
|
try:
|
|
146
146
|
async for response in agen:
|
|
147
|
-
subdomains = self.parse_results(response, query)
|
|
147
|
+
subdomains = await self.parse_results(response, query)
|
|
148
148
|
self.verbose(f'Got {len(subdomains):,} subdomains for "{query}"')
|
|
149
149
|
if not subdomains:
|
|
150
150
|
break
|
bbot/modules/trickest.py
CHANGED
|
@@ -36,7 +36,7 @@ class Trickest(subdomain_enum_apikey):
|
|
|
36
36
|
url += "&limit={page_size}&offset={offset}&select=hostname&orderby=hostname"
|
|
37
37
|
return url
|
|
38
38
|
|
|
39
|
-
def parse_results(self, j, query):
|
|
39
|
+
async def parse_results(self, j, query):
|
|
40
40
|
results = j.get("results", [])
|
|
41
41
|
subdomains = set()
|
|
42
42
|
for item in results:
|
bbot/modules/virustotal.py
CHANGED
|
@@ -24,11 +24,6 @@ class virustotal(subdomain_enum_apikey):
|
|
|
24
24
|
kwargs["headers"]["x-apikey"] = self.api_key
|
|
25
25
|
return url, kwargs
|
|
26
26
|
|
|
27
|
-
def parse_results(self, r, query):
|
|
28
|
-
results = set()
|
|
27
|
+
async def parse_results(self, r, query):
|
|
29
28
|
text = getattr(r, "text", "")
|
|
30
|
-
|
|
31
|
-
match = match.lower()
|
|
32
|
-
if match.endswith(query):
|
|
33
|
-
results.add(match)
|
|
34
|
-
return results
|
|
29
|
+
return await self.scan.extract_in_scope_hostnames(text)
|
bbot/modules/zoomeye.py
CHANGED
|
@@ -60,7 +60,7 @@ class zoomeye(subdomain_enum_apikey):
|
|
|
60
60
|
agen = self.api_page_iter(url)
|
|
61
61
|
try:
|
|
62
62
|
async for j in agen:
|
|
63
|
-
r = list(self.parse_results(j))
|
|
63
|
+
r = list(await self.parse_results(j))
|
|
64
64
|
if r:
|
|
65
65
|
results.update(set(r))
|
|
66
66
|
if not r or i >= (self.max_pages - 1):
|
|
@@ -70,6 +70,8 @@ class zoomeye(subdomain_enum_apikey):
|
|
|
70
70
|
agen.aclose()
|
|
71
71
|
return results
|
|
72
72
|
|
|
73
|
-
def parse_results(self, r):
|
|
73
|
+
async def parse_results(self, r):
|
|
74
|
+
results = set()
|
|
74
75
|
for entry in r.get("list", []):
|
|
75
|
-
|
|
76
|
+
results.add(entry["name"])
|
|
77
|
+
return results
|
bbot/presets/fast.yml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
description: Scan only the provided targets as fast as possible - no extra discovery
|
|
2
|
+
|
|
3
|
+
exclude_modules:
|
|
4
|
+
- excavate
|
|
5
|
+
|
|
6
|
+
config:
|
|
7
|
+
# only scan the exact targets specified
|
|
8
|
+
scope:
|
|
9
|
+
strict: true
|
|
10
|
+
# speed up dns resolution by doing A/AAAA only - not MX/NS/SRV/etc
|
|
11
|
+
dns:
|
|
12
|
+
minimal: true
|
|
13
|
+
# essential speculation only
|
|
14
|
+
modules:
|
|
15
|
+
speculate:
|
|
16
|
+
essential_only: true
|
bbot/presets/spider.yml
CHANGED
bbot/scanner/manager.py
CHANGED
|
@@ -38,7 +38,7 @@ class ScanIngress(BaseInterceptModule):
|
|
|
38
38
|
- It also marks the Scan object as finished with initialization by setting `_finished_init` to True.
|
|
39
39
|
"""
|
|
40
40
|
if events is None:
|
|
41
|
-
events = self.scan.target.events
|
|
41
|
+
events = self.scan.target.seeds.events
|
|
42
42
|
async with self.scan._acatch(self.init_events), self._task_counter.count(self.init_events):
|
|
43
43
|
sorted_events = sorted(events, key=lambda e: len(e.data))
|
|
44
44
|
for event in [self.scan.root_event] + sorted_events:
|
|
@@ -49,7 +49,6 @@ class ScanIngress(BaseInterceptModule):
|
|
|
49
49
|
event.parent = self.scan.root_event
|
|
50
50
|
if event.module is None:
|
|
51
51
|
event.module = self.scan._make_dummy_module(name="TARGET", _type="TARGET")
|
|
52
|
-
event.add_tag("target")
|
|
53
52
|
if event != self.scan.root_event:
|
|
54
53
|
event.discovery_context = f"Scan {self.scan.name} seeded with " + "{event.type}: {event.data}"
|
|
55
54
|
self.verbose(f"Target: {event}")
|
bbot/scanner/preset/args.py
CHANGED
|
@@ -91,7 +91,6 @@ class BBOTArgs:
|
|
|
91
91
|
*self.parsed.targets,
|
|
92
92
|
whitelist=self.parsed.whitelist,
|
|
93
93
|
blacklist=self.parsed.blacklist,
|
|
94
|
-
strict_scope=self.parsed.strict_scope,
|
|
95
94
|
name="args_preset",
|
|
96
95
|
)
|
|
97
96
|
|
|
@@ -149,6 +148,9 @@ class BBOTArgs:
|
|
|
149
148
|
if self.parsed.force:
|
|
150
149
|
args_preset.force_start = self.parsed.force
|
|
151
150
|
|
|
151
|
+
if self.parsed.proxy:
|
|
152
|
+
args_preset.core.merge_custom({"web": {"http_proxy": self.parsed.proxy}})
|
|
153
|
+
|
|
152
154
|
if self.parsed.custom_headers:
|
|
153
155
|
args_preset.core.merge_custom({"web": {"http_headers": self.parsed.custom_headers}})
|
|
154
156
|
|
|
@@ -165,6 +167,10 @@ class BBOTArgs:
|
|
|
165
167
|
except Exception as e:
|
|
166
168
|
raise BBOTArgumentError(f'Error parsing command-line config option: "{config_arg}": {e}')
|
|
167
169
|
|
|
170
|
+
# strict scope
|
|
171
|
+
if self.parsed.strict_scope:
|
|
172
|
+
args_preset.core.merge_custom({"scope": {"strict": True}})
|
|
173
|
+
|
|
168
174
|
return args_preset
|
|
169
175
|
|
|
170
176
|
def create_parser(self, *args, **kwargs):
|
|
@@ -217,7 +223,7 @@ class BBOTArgs:
|
|
|
217
223
|
"--modules",
|
|
218
224
|
nargs="+",
|
|
219
225
|
default=[],
|
|
220
|
-
help=f'Modules to enable. Choices: {",".join(self.preset.module_loader.scan_module_choices)}',
|
|
226
|
+
help=f'Modules to enable. Choices: {",".join(sorted(self.preset.module_loader.scan_module_choices))}',
|
|
221
227
|
metavar="MODULE",
|
|
222
228
|
)
|
|
223
229
|
modules.add_argument("-l", "--list-modules", action="store_true", help=f"List available modules.")
|
|
@@ -232,7 +238,7 @@ class BBOTArgs:
|
|
|
232
238
|
"--flags",
|
|
233
239
|
nargs="+",
|
|
234
240
|
default=[],
|
|
235
|
-
help=f'Enable modules by flag. Choices: {",".join(self.preset.module_loader.flag_choices)}',
|
|
241
|
+
help=f'Enable modules by flag. Choices: {",".join(sorted(self.preset.module_loader.flag_choices))}',
|
|
236
242
|
metavar="FLAG",
|
|
237
243
|
)
|
|
238
244
|
modules.add_argument("-lf", "--list-flags", action="store_true", help=f"List available flags.")
|
|
@@ -265,6 +271,11 @@ class BBOTArgs:
|
|
|
265
271
|
help="Run scan even in the case of condition violations or failed module setups",
|
|
266
272
|
)
|
|
267
273
|
scan.add_argument("-y", "--yes", action="store_true", help="Skip scan confirmation prompt")
|
|
274
|
+
scan.add_argument(
|
|
275
|
+
"--fast-mode",
|
|
276
|
+
action="store_true",
|
|
277
|
+
help="Scan only the provided targets as fast as possible, with no extra discovery",
|
|
278
|
+
)
|
|
268
279
|
scan.add_argument("--dry-run", action="store_true", help=f"Abort before executing scan")
|
|
269
280
|
scan.add_argument(
|
|
270
281
|
"--current-preset",
|
|
@@ -289,7 +300,7 @@ class BBOTArgs:
|
|
|
289
300
|
"--output-modules",
|
|
290
301
|
nargs="+",
|
|
291
302
|
default=[],
|
|
292
|
-
help=f'Output module(s). Choices: {",".join(self.preset.module_loader.output_module_choices)}',
|
|
303
|
+
help=f'Output module(s). Choices: {",".join(sorted(self.preset.module_loader.output_module_choices))}',
|
|
293
304
|
metavar="MODULE",
|
|
294
305
|
)
|
|
295
306
|
output.add_argument("--json", "-j", action="store_true", help="Output scan data in JSON format")
|
|
@@ -310,6 +321,7 @@ class BBOTArgs:
|
|
|
310
321
|
|
|
311
322
|
misc = p.add_argument_group(title="Misc")
|
|
312
323
|
misc.add_argument("--version", action="store_true", help="show BBOT version and exit")
|
|
324
|
+
misc.add_argument("--proxy", help="Use this proxy for all HTTP requests", metavar="HTTP_PROXY")
|
|
313
325
|
misc.add_argument(
|
|
314
326
|
"-H",
|
|
315
327
|
"--custom-headers",
|
|
@@ -359,6 +371,10 @@ class BBOTArgs:
|
|
|
359
371
|
custom_headers_dict[k] = v
|
|
360
372
|
self.parsed.custom_headers = custom_headers_dict
|
|
361
373
|
|
|
374
|
+
# --fast-mode
|
|
375
|
+
if self.parsed.fast_mode:
|
|
376
|
+
self.parsed.preset += ["fast"]
|
|
377
|
+
|
|
362
378
|
def validate(self):
|
|
363
379
|
# validate config options
|
|
364
380
|
sentinel = object()
|
bbot/scanner/preset/path.py
CHANGED
|
@@ -33,7 +33,9 @@ class PresetPath:
|
|
|
33
33
|
if "/" in str(filename):
|
|
34
34
|
if filename_path.parent not in paths_to_search:
|
|
35
35
|
paths_to_search.append(filename_path.parent)
|
|
36
|
-
log.debug(
|
|
36
|
+
log.debug(
|
|
37
|
+
f"Searching for preset in {[str(p) for p in paths_to_search]}, file candidates: {file_candidates_str}"
|
|
38
|
+
)
|
|
37
39
|
for path in paths_to_search:
|
|
38
40
|
for candidate in file_candidates:
|
|
39
41
|
for file in path.rglob(candidate):
|
bbot/scanner/preset/preset.py
CHANGED
|
@@ -47,7 +47,6 @@ class Preset:
|
|
|
47
47
|
target (Target): Target(s) of scan.
|
|
48
48
|
whitelist (Target): Scan whitelist (by default this is the same as `target`).
|
|
49
49
|
blacklist (Target): Scan blacklist (this takes ultimate precedence).
|
|
50
|
-
strict_scope (bool): If True, subdomains of targets are not considered to be in-scope.
|
|
51
50
|
helpers (ConfigAwareHelper): Helper containing various reusable functions, regexes, etc.
|
|
52
51
|
output_dir (pathlib.Path): Output directory for scan.
|
|
53
52
|
scan_name (str): Name of scan. Defaults to random value, e.g. "demonic_jimmy".
|
|
@@ -87,7 +86,6 @@ class Preset:
|
|
|
87
86
|
*targets,
|
|
88
87
|
whitelist=None,
|
|
89
88
|
blacklist=None,
|
|
90
|
-
strict_scope=False,
|
|
91
89
|
modules=None,
|
|
92
90
|
output_modules=None,
|
|
93
91
|
exclude_modules=None,
|
|
@@ -117,7 +115,6 @@ class Preset:
|
|
|
117
115
|
*targets (str): Target(s) to scan. Types supported: hostnames, IPs, CIDRs, emails, open ports.
|
|
118
116
|
whitelist (list, optional): Whitelisted target(s) to scan. Defaults to the same as `targets`.
|
|
119
117
|
blacklist (list, optional): Blacklisted target(s). Takes ultimate precedence. Defaults to empty.
|
|
120
|
-
strict_scope (bool, optional): If True, subdomains of targets are not in-scope.
|
|
121
118
|
modules (list[str], optional): List of scan modules to enable for the scan. Defaults to empty list.
|
|
122
119
|
output_modules (list[str], optional): List of output modules to use. Defaults to csv, human, and json.
|
|
123
120
|
exclude_modules (list[str], optional): List of modules to exclude from the scan.
|
|
@@ -234,7 +231,6 @@ class Preset:
|
|
|
234
231
|
self.module_dirs = module_dirs
|
|
235
232
|
|
|
236
233
|
# target / whitelist / blacklist
|
|
237
|
-
self.strict_scope = strict_scope
|
|
238
234
|
# these are temporary receptacles until they all get .baked() together
|
|
239
235
|
self._seeds = set(targets if targets else [])
|
|
240
236
|
self._whitelist = set(whitelist) if whitelist else whitelist
|
|
@@ -245,7 +241,7 @@ class Preset:
|
|
|
245
241
|
# "presets" is alias to "include"
|
|
246
242
|
if presets and include:
|
|
247
243
|
raise ValueError(
|
|
248
|
-
'Cannot use both "presets" and "include" args at the same time (presets is
|
|
244
|
+
'Cannot use both "presets" and "include" args at the same time (presets is an alias to include). Please pick one or the other :)'
|
|
249
245
|
)
|
|
250
246
|
if presets and not include:
|
|
251
247
|
include = presets
|
|
@@ -274,6 +270,12 @@ class Preset:
|
|
|
274
270
|
raise ValueError("Cannot access target before preset is baked (use ._seeds instead)")
|
|
275
271
|
return self._target
|
|
276
272
|
|
|
273
|
+
@property
|
|
274
|
+
def seeds(self):
|
|
275
|
+
if self._seeds is None:
|
|
276
|
+
raise ValueError("Cannot access target before preset is baked (use ._seeds instead)")
|
|
277
|
+
return self.target.seeds
|
|
278
|
+
|
|
277
279
|
@property
|
|
278
280
|
def whitelist(self):
|
|
279
281
|
if self._target is None:
|
|
@@ -353,7 +355,6 @@ class Preset:
|
|
|
353
355
|
else:
|
|
354
356
|
self._whitelist.update(other._whitelist)
|
|
355
357
|
self._blacklist.update(other._blacklist)
|
|
356
|
-
self.strict_scope = self.strict_scope or other.strict_scope
|
|
357
358
|
|
|
358
359
|
# module dirs
|
|
359
360
|
self.module_dirs = self.module_dirs.union(other.module_dirs)
|
|
@@ -537,6 +538,14 @@ class Preset:
|
|
|
537
538
|
def web_config(self):
|
|
538
539
|
return self.core.config.get("web", {})
|
|
539
540
|
|
|
541
|
+
@property
|
|
542
|
+
def scope_config(self):
|
|
543
|
+
return self.config.get("scope", {})
|
|
544
|
+
|
|
545
|
+
@property
|
|
546
|
+
def strict_scope(self):
|
|
547
|
+
return self.scope_config.get("strict", False)
|
|
548
|
+
|
|
540
549
|
def apply_log_level(self, apply_core=False):
|
|
541
550
|
# silent takes precedence
|
|
542
551
|
if self.silent:
|
|
@@ -635,7 +644,6 @@ class Preset:
|
|
|
635
644
|
debug=preset_dict.get("debug", False),
|
|
636
645
|
silent=preset_dict.get("silent", False),
|
|
637
646
|
config=preset_dict.get("config"),
|
|
638
|
-
strict_scope=preset_dict.get("strict_scope", False),
|
|
639
647
|
module_dirs=preset_dict.get("module_dirs", []),
|
|
640
648
|
include=list(preset_dict.get("include", [])),
|
|
641
649
|
scan_name=preset_dict.get("scan_name"),
|
|
@@ -753,19 +761,17 @@ class Preset:
|
|
|
753
761
|
|
|
754
762
|
# scope
|
|
755
763
|
if include_target:
|
|
756
|
-
target = sorted(
|
|
764
|
+
target = sorted(self.target.seeds.inputs)
|
|
757
765
|
whitelist = []
|
|
758
766
|
if self.target.whitelist is not None:
|
|
759
|
-
whitelist = sorted(
|
|
760
|
-
blacklist = sorted(
|
|
767
|
+
whitelist = sorted(self.target.whitelist.inputs)
|
|
768
|
+
blacklist = sorted(self.target.blacklist.inputs)
|
|
761
769
|
if target:
|
|
762
770
|
preset_dict["target"] = target
|
|
763
771
|
if whitelist and whitelist != target:
|
|
764
772
|
preset_dict["whitelist"] = whitelist
|
|
765
773
|
if blacklist:
|
|
766
774
|
preset_dict["blacklist"] = blacklist
|
|
767
|
-
if self.strict_scope:
|
|
768
|
-
preset_dict["strict_scope"] = True
|
|
769
775
|
|
|
770
776
|
# flags + modules
|
|
771
777
|
if self.require_flags:
|
bbot/scanner/scanner.py
CHANGED
|
@@ -269,7 +269,7 @@ class Scanner:
|
|
|
269
269
|
f.write(self.preset.to_yaml())
|
|
270
270
|
|
|
271
271
|
# log scan overview
|
|
272
|
-
start_msg = f"Scan
|
|
272
|
+
start_msg = f"Scan seeded with {len(self.seeds):,} targets"
|
|
273
273
|
details = []
|
|
274
274
|
if self.whitelist != self.target:
|
|
275
275
|
details.append(f"{len(self.whitelist):,} in whitelist")
|
|
@@ -362,7 +362,8 @@ class Scanner:
|
|
|
362
362
|
|
|
363
363
|
# distribute seed events
|
|
364
364
|
self.init_events_task = asyncio.create_task(
|
|
365
|
-
self.ingress_module.init_events(self.target.events),
|
|
365
|
+
self.ingress_module.init_events(self.target.seeds.events),
|
|
366
|
+
name=f"{self.name}.ingress_module.init_events()",
|
|
366
367
|
)
|
|
367
368
|
|
|
368
369
|
# main scan loop
|
|
@@ -896,6 +897,10 @@ class Scanner:
|
|
|
896
897
|
def target(self):
|
|
897
898
|
return self.preset.target
|
|
898
899
|
|
|
900
|
+
@property
|
|
901
|
+
def seeds(self):
|
|
902
|
+
return self.preset.seeds
|
|
903
|
+
|
|
899
904
|
@property
|
|
900
905
|
def whitelist(self):
|
|
901
906
|
return self.preset.whitelist
|