bbot 2.0.1.4720rc0__py3-none-any.whl → 2.3.0.5397rc0__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 +3 -7
- bbot/core/config/files.py +0 -1
- bbot/core/config/logger.py +34 -4
- bbot/core/core.py +21 -4
- bbot/core/engine.py +9 -8
- bbot/core/event/base.py +131 -52
- bbot/core/helpers/bloom.py +10 -3
- bbot/core/helpers/command.py +8 -7
- bbot/core/helpers/depsinstaller/installer.py +31 -13
- bbot/core/helpers/diff.py +10 -10
- bbot/core/helpers/dns/brute.py +7 -4
- bbot/core/helpers/dns/dns.py +1 -2
- bbot/core/helpers/dns/engine.py +4 -6
- bbot/core/helpers/dns/helpers.py +2 -2
- bbot/core/helpers/dns/mock.py +0 -1
- bbot/core/helpers/files.py +1 -1
- bbot/core/helpers/helper.py +7 -4
- bbot/core/helpers/interactsh.py +3 -3
- bbot/core/helpers/libmagic.py +65 -0
- bbot/core/helpers/misc.py +65 -22
- bbot/core/helpers/names_generator.py +17 -3
- bbot/core/helpers/process.py +0 -20
- bbot/core/helpers/regex.py +1 -1
- bbot/core/helpers/regexes.py +12 -6
- bbot/core/helpers/validators.py +1 -2
- bbot/core/helpers/web/client.py +1 -1
- bbot/core/helpers/web/engine.py +1 -2
- bbot/core/helpers/web/web.py +4 -114
- bbot/core/helpers/wordcloud.py +5 -5
- bbot/core/modules.py +36 -27
- bbot/core/multiprocess.py +58 -0
- bbot/core/shared_deps.py +46 -3
- bbot/db/sql/models.py +147 -0
- bbot/defaults.yml +11 -9
- bbot/modules/anubisdb.py +2 -2
- bbot/modules/apkpure.py +63 -0
- bbot/modules/azure_tenant.py +2 -2
- bbot/modules/baddns.py +35 -19
- bbot/modules/baddns_direct.py +92 -0
- bbot/modules/baddns_zone.py +3 -8
- bbot/modules/badsecrets.py +4 -3
- bbot/modules/base.py +195 -51
- bbot/modules/bevigil.py +7 -7
- bbot/modules/binaryedge.py +7 -4
- bbot/modules/bufferoverrun.py +47 -0
- bbot/modules/builtwith.py +6 -10
- bbot/modules/bypass403.py +5 -5
- bbot/modules/c99.py +10 -7
- bbot/modules/censys.py +9 -13
- bbot/modules/certspotter.py +5 -3
- bbot/modules/chaos.py +9 -7
- bbot/modules/code_repository.py +1 -0
- bbot/modules/columbus.py +3 -3
- bbot/modules/crt.py +5 -3
- bbot/modules/deadly/dastardly.py +1 -1
- bbot/modules/deadly/ffuf.py +9 -9
- bbot/modules/deadly/nuclei.py +3 -3
- bbot/modules/deadly/vhost.py +4 -3
- bbot/modules/dehashed.py +1 -1
- bbot/modules/digitorus.py +1 -1
- bbot/modules/dnsbimi.py +145 -0
- bbot/modules/dnscaa.py +3 -3
- bbot/modules/dnsdumpster.py +4 -4
- bbot/modules/dnstlsrpt.py +144 -0
- bbot/modules/docker_pull.py +7 -5
- bbot/modules/dockerhub.py +2 -2
- bbot/modules/dotnetnuke.py +18 -19
- bbot/modules/emailformat.py +1 -1
- bbot/modules/extractous.py +122 -0
- bbot/modules/filedownload.py +9 -7
- bbot/modules/fullhunt.py +7 -4
- bbot/modules/generic_ssrf.py +5 -5
- bbot/modules/github_codesearch.py +3 -2
- bbot/modules/github_org.py +4 -4
- bbot/modules/github_workflows.py +4 -4
- bbot/modules/gitlab.py +2 -5
- bbot/modules/google_playstore.py +93 -0
- bbot/modules/gowitness.py +48 -50
- bbot/modules/hackertarget.py +5 -3
- bbot/modules/host_header.py +5 -5
- bbot/modules/httpx.py +1 -4
- bbot/modules/hunterio.py +3 -9
- bbot/modules/iis_shortnames.py +19 -30
- bbot/modules/internal/cloudcheck.py +27 -12
- bbot/modules/internal/dnsresolve.py +22 -20
- bbot/modules/internal/excavate.py +85 -48
- bbot/modules/internal/speculate.py +41 -32
- bbot/modules/internetdb.py +4 -2
- bbot/modules/ip2location.py +3 -5
- bbot/modules/ipneighbor.py +1 -1
- bbot/modules/ipstack.py +3 -8
- bbot/modules/jadx.py +87 -0
- bbot/modules/leakix.py +11 -10
- bbot/modules/myssl.py +2 -2
- bbot/modules/newsletters.py +2 -2
- bbot/modules/otx.py +5 -3
- bbot/modules/output/asset_inventory.py +7 -7
- bbot/modules/output/base.py +1 -1
- bbot/modules/output/csv.py +1 -1
- bbot/modules/output/http.py +20 -14
- bbot/modules/output/mysql.py +51 -0
- bbot/modules/output/neo4j.py +7 -2
- bbot/modules/output/postgres.py +49 -0
- bbot/modules/output/slack.py +0 -1
- bbot/modules/output/sqlite.py +29 -0
- bbot/modules/output/stdout.py +2 -2
- bbot/modules/output/teams.py +107 -6
- bbot/modules/paramminer_headers.py +5 -8
- bbot/modules/passivetotal.py +13 -13
- bbot/modules/portscan.py +32 -6
- bbot/modules/postman.py +50 -126
- bbot/modules/postman_download.py +220 -0
- bbot/modules/rapiddns.py +3 -8
- bbot/modules/report/asn.py +11 -11
- bbot/modules/robots.py +3 -3
- bbot/modules/securitytrails.py +7 -10
- bbot/modules/securitytxt.py +1 -1
- bbot/modules/shodan_dns.py +7 -9
- bbot/modules/sitedossier.py +1 -1
- bbot/modules/skymem.py +2 -2
- bbot/modules/social.py +2 -1
- bbot/modules/subdomaincenter.py +1 -1
- bbot/modules/subdomainradar.py +160 -0
- bbot/modules/telerik.py +8 -8
- bbot/modules/templates/bucket.py +1 -1
- bbot/modules/templates/github.py +22 -14
- bbot/modules/templates/postman.py +21 -0
- bbot/modules/templates/shodan.py +14 -13
- bbot/modules/templates/sql.py +95 -0
- bbot/modules/templates/subdomain_enum.py +51 -16
- bbot/modules/templates/webhook.py +2 -4
- bbot/modules/trickest.py +8 -37
- bbot/modules/trufflehog.py +10 -12
- bbot/modules/url_manipulation.py +3 -3
- bbot/modules/urlscan.py +1 -1
- bbot/modules/viewdns.py +1 -1
- bbot/modules/virustotal.py +8 -30
- bbot/modules/wafw00f.py +1 -1
- bbot/modules/wayback.py +1 -1
- bbot/modules/wpscan.py +17 -11
- bbot/modules/zoomeye.py +11 -6
- bbot/presets/baddns-thorough.yml +12 -0
- bbot/presets/fast.yml +16 -0
- bbot/presets/kitchen-sink.yml +1 -0
- bbot/presets/spider.yml +4 -0
- bbot/presets/subdomain-enum.yml +7 -7
- bbot/scanner/manager.py +5 -16
- bbot/scanner/preset/args.py +44 -26
- bbot/scanner/preset/environ.py +7 -2
- bbot/scanner/preset/path.py +7 -4
- bbot/scanner/preset/preset.py +36 -23
- bbot/scanner/scanner.py +172 -62
- bbot/scanner/target.py +236 -434
- bbot/scripts/docs.py +1 -1
- bbot/test/bbot_fixtures.py +13 -3
- bbot/test/conftest.py +132 -100
- bbot/test/fastapi_test.py +17 -0
- bbot/test/owasp_mastg.apk +0 -0
- bbot/test/run_tests.sh +4 -4
- bbot/test/test.conf +2 -0
- bbot/test/test_step_1/test_bbot_fastapi.py +82 -0
- bbot/test/test_step_1/test_bloom_filter.py +2 -0
- bbot/test/test_step_1/test_cli.py +138 -64
- bbot/test/test_step_1/test_dns.py +62 -25
- bbot/test/test_step_1/test_engine.py +17 -17
- bbot/test/test_step_1/test_events.py +183 -28
- bbot/test/test_step_1/test_helpers.py +64 -28
- bbot/test/test_step_1/test_manager_deduplication.py +1 -1
- bbot/test/test_step_1/test_manager_scope_accuracy.py +333 -330
- bbot/test/test_step_1/test_modules_basic.py +68 -70
- bbot/test/test_step_1/test_presets.py +184 -96
- bbot/test/test_step_1/test_python_api.py +7 -2
- bbot/test/test_step_1/test_regexes.py +35 -5
- bbot/test/test_step_1/test_scan.py +39 -5
- bbot/test/test_step_1/test_scope.py +4 -3
- bbot/test/test_step_1/test_target.py +243 -145
- bbot/test/test_step_1/test_web.py +14 -8
- bbot/test/test_step_2/module_tests/base.py +15 -7
- bbot/test/test_step_2/module_tests/test_module_anubisdb.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_apkpure.py +71 -0
- bbot/test/test_step_2/module_tests/test_module_asset_inventory.py +0 -1
- bbot/test/test_step_2/module_tests/test_module_azure_realm.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_baddns.py +6 -6
- bbot/test/test_step_2/module_tests/test_module_baddns_direct.py +62 -0
- bbot/test/test_step_2/module_tests/test_module_bevigil.py +29 -2
- bbot/test/test_step_2/module_tests/test_module_binaryedge.py +4 -2
- bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_bucket_azure.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py +35 -0
- bbot/test/test_step_2/module_tests/test_module_builtwith.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_bypass403.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_c99.py +126 -0
- bbot/test/test_step_2/module_tests/test_module_censys.py +4 -1
- bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +4 -0
- bbot/test/test_step_2/module_tests/test_module_code_repository.py +11 -1
- bbot/test/test_step_2/module_tests/test_module_columbus.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_credshed.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_dastardly.py +2 -1
- bbot/test/test_step_2/module_tests/test_module_dehashed.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_digitorus.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_discord.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_dnsbimi.py +103 -0
- bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +9 -10
- bbot/test/test_step_2/module_tests/test_module_dnsbrute_mutations.py +1 -2
- bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +1 -2
- bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py +64 -0
- bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +0 -8
- bbot/test/test_step_2/module_tests/test_module_excavate.py +17 -37
- bbot/test/test_step_2/module_tests/test_module_extractous.py +54 -0
- bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_filedownload.py +14 -14
- bbot/test/test_step_2/module_tests/test_module_git_clone.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_github_org.py +19 -8
- bbot/test/test_step_2/module_tests/test_module_github_workflows.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_gitlab.py +9 -4
- bbot/test/test_step_2/module_tests/test_module_google_playstore.py +83 -0
- bbot/test/test_step_2/module_tests/test_module_gowitness.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_host_header.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_http.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_httpx.py +10 -8
- bbot/test/test_step_2/module_tests/test_module_hunterio.py +68 -4
- bbot/test/test_step_2/module_tests/test_module_jadx.py +55 -0
- bbot/test/test_step_2/module_tests/test_module_json.py +22 -9
- bbot/test/test_step_2/module_tests/test_module_leakix.py +7 -3
- bbot/test/test_step_2/module_tests/test_module_mysql.py +76 -0
- bbot/test/test_step_2/module_tests/test_module_myssl.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_neo4j.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_newsletters.py +6 -6
- bbot/test/test_step_2/module_tests/test_module_ntlm.py +7 -7
- bbot/test/test_step_2/module_tests/test_module_oauth.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_otx.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_paramminer_cookies.py +1 -2
- bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +0 -6
- bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +2 -9
- bbot/test/test_step_2/module_tests/test_module_passivetotal.py +3 -1
- bbot/test/test_step_2/module_tests/test_module_portscan.py +9 -8
- bbot/test/test_step_2/module_tests/test_module_postgres.py +74 -0
- bbot/test/test_step_2/module_tests/test_module_postman.py +84 -253
- bbot/test/test_step_2/module_tests/test_module_postman_download.py +439 -0
- bbot/test/test_step_2/module_tests/test_module_rapiddns.py +93 -1
- bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +20 -1
- bbot/test/test_step_2/module_tests/test_module_sitedossier.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_smuggler.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_social.py +11 -1
- bbot/test/test_step_2/module_tests/test_module_speculate.py +2 -6
- bbot/test/test_step_2/module_tests/test_module_splunk.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_sqlite.py +18 -0
- bbot/test/test_step_2/module_tests/test_module_sslcert.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_stdout.py +5 -3
- bbot/test/test_step_2/module_tests/test_module_subdomaincenter.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_subdomainradar.py +208 -0
- bbot/test/test_step_2/module_tests/test_module_subdomains.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_teams.py +8 -6
- bbot/test/test_step_2/module_tests/test_module_telerik.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_trufflehog.py +317 -14
- bbot/test/test_step_2/module_tests/test_module_wayback.py +1 -1
- bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +2 -2
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/METADATA +48 -18
- bbot-2.3.0.5397rc0.dist-info/RECORD +421 -0
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/WHEEL +1 -1
- bbot/modules/unstructured.py +0 -163
- bbot/test/test_step_2/module_tests/test_module_unstructured.py +0 -102
- bbot-2.0.1.4720rc0.dist-info/RECORD +0 -387
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/LICENSE +0 -0
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/entry_points.txt +0 -0
bbot/presets/subdomain-enum.yml
CHANGED
|
@@ -13,10 +13,10 @@ config:
|
|
|
13
13
|
threads: 25
|
|
14
14
|
brute_threads: 1000
|
|
15
15
|
# put your API keys here
|
|
16
|
-
modules:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
# modules:
|
|
17
|
+
# github:
|
|
18
|
+
# api_key: ""
|
|
19
|
+
# chaos:
|
|
20
|
+
# api_key: ""
|
|
21
|
+
# securitytrails:
|
|
22
|
+
# api_key: ""
|
bbot/scanner/manager.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from contextlib import suppress
|
|
3
3
|
|
|
4
|
-
from bbot.modules.base import
|
|
4
|
+
from bbot.modules.base import BaseInterceptModule
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class ScanIngress(
|
|
7
|
+
class ScanIngress(BaseInterceptModule):
|
|
8
8
|
"""
|
|
9
9
|
This is always the first intercept module in the chain, responsible for basic scope checks
|
|
10
10
|
|
|
@@ -15,9 +15,7 @@ class ScanIngress(InterceptModule):
|
|
|
15
15
|
# accept all events regardless of scope distance
|
|
16
16
|
scope_distance_modifier = None
|
|
17
17
|
_name = "_scan_ingress"
|
|
18
|
-
|
|
19
|
-
# small queue size so we don't drain modules' outgoing queues
|
|
20
|
-
_qsize = 10
|
|
18
|
+
_qsize = -1
|
|
21
19
|
|
|
22
20
|
@property
|
|
23
21
|
def priority(self):
|
|
@@ -40,7 +38,7 @@ class ScanIngress(InterceptModule):
|
|
|
40
38
|
- It also marks the Scan object as finished with initialization by setting `_finished_init` to True.
|
|
41
39
|
"""
|
|
42
40
|
if events is None:
|
|
43
|
-
events = self.scan.target.events
|
|
41
|
+
events = self.scan.target.seeds.events
|
|
44
42
|
async with self.scan._acatch(self.init_events), self._task_counter.count(self.init_events):
|
|
45
43
|
sorted_events = sorted(events, key=lambda e: len(e.data))
|
|
46
44
|
for event in [self.scan.root_event] + sorted_events:
|
|
@@ -51,7 +49,6 @@ class ScanIngress(InterceptModule):
|
|
|
51
49
|
event.parent = self.scan.root_event
|
|
52
50
|
if event.module is None:
|
|
53
51
|
event.module = self.scan._make_dummy_module(name="TARGET", _type="TARGET")
|
|
54
|
-
event.add_tag("target")
|
|
55
52
|
if event != self.scan.root_event:
|
|
56
53
|
event.discovery_context = f"Scan {self.scan.name} seeded with " + "{event.type}: {event.data}"
|
|
57
54
|
self.verbose(f"Target: {event}")
|
|
@@ -115,14 +112,6 @@ class ScanIngress(InterceptModule):
|
|
|
115
112
|
# nerf event's priority if it's not in scope
|
|
116
113
|
event.module_priority += event.scope_distance
|
|
117
114
|
|
|
118
|
-
async def forward_event(self, event, kwargs):
|
|
119
|
-
# if a module qualifies for "quick-emit", we skip all the intermediate modules like dns and cloud
|
|
120
|
-
# and forward it straight to the egress module
|
|
121
|
-
if event.quick_emit:
|
|
122
|
-
await self.scan.egress_module.queue_event(event, kwargs)
|
|
123
|
-
else:
|
|
124
|
-
await super().forward_event(event, kwargs)
|
|
125
|
-
|
|
126
115
|
@property
|
|
127
116
|
def non_intercept_modules(self):
|
|
128
117
|
if self._non_intercept_modules is None:
|
|
@@ -169,7 +158,7 @@ class ScanIngress(InterceptModule):
|
|
|
169
158
|
return False
|
|
170
159
|
|
|
171
160
|
|
|
172
|
-
class ScanEgress(
|
|
161
|
+
class ScanEgress(BaseInterceptModule):
|
|
173
162
|
"""
|
|
174
163
|
This is always the last intercept module in the chain, responsible for executing and acting on the
|
|
175
164
|
`abort_if` and `on_success_callback` functions.
|
bbot/scanner/preset/args.py
CHANGED
|
@@ -10,7 +10,6 @@ log = logging.getLogger("bbot.presets.args")
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class BBOTArgs:
|
|
13
|
-
|
|
14
13
|
# module config options to exclude from validation
|
|
15
14
|
exclude_from_validation = re.compile(r".*modules\.[a-z0-9_]+\.(?:batch_size|module_threads)$")
|
|
16
15
|
|
|
@@ -91,18 +90,9 @@ class BBOTArgs:
|
|
|
91
90
|
*self.parsed.targets,
|
|
92
91
|
whitelist=self.parsed.whitelist,
|
|
93
92
|
blacklist=self.parsed.blacklist,
|
|
94
|
-
strict_scope=self.parsed.strict_scope,
|
|
95
93
|
name="args_preset",
|
|
96
94
|
)
|
|
97
95
|
|
|
98
|
-
# then we set verbosity levels (so if the user enables -d they can see debug output)
|
|
99
|
-
if self.parsed.silent:
|
|
100
|
-
args_preset.silent = True
|
|
101
|
-
if self.parsed.verbose:
|
|
102
|
-
args_preset.verbose = True
|
|
103
|
-
if self.parsed.debug:
|
|
104
|
-
args_preset.debug = True
|
|
105
|
-
|
|
106
96
|
# then we load requested preset
|
|
107
97
|
# this is important so we can load custom module directories, pull in custom flags, module config options, etc.
|
|
108
98
|
for preset_arg in self.parsed.preset:
|
|
@@ -113,6 +103,14 @@ class BBOTArgs:
|
|
|
113
103
|
except Exception as e:
|
|
114
104
|
raise BBOTArgumentError(f'Error parsing preset "{preset_arg}": {e}')
|
|
115
105
|
|
|
106
|
+
# then we set verbosity levels (so if the user enables -d they can see debug output)
|
|
107
|
+
if self.parsed.silent:
|
|
108
|
+
args_preset.silent = True
|
|
109
|
+
if self.parsed.verbose:
|
|
110
|
+
args_preset.verbose = True
|
|
111
|
+
if self.parsed.debug:
|
|
112
|
+
args_preset.debug = True
|
|
113
|
+
|
|
116
114
|
# modules + flags
|
|
117
115
|
args_preset.exclude_modules.update(set(self.parsed.exclude_modules))
|
|
118
116
|
args_preset.exclude_flags.update(set(self.parsed.exclude_flags))
|
|
@@ -142,9 +140,15 @@ class BBOTArgs:
|
|
|
142
140
|
args_preset.core.custom_config["deps_behavior"] = "ignore_failed"
|
|
143
141
|
|
|
144
142
|
# other scan options
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
if self.parsed.name is not None:
|
|
144
|
+
args_preset.scan_name = self.parsed.name
|
|
145
|
+
if self.parsed.output_dir is not None:
|
|
146
|
+
args_preset.output_dir = self.parsed.output_dir
|
|
147
|
+
if self.parsed.force:
|
|
148
|
+
args_preset.force_start = self.parsed.force
|
|
149
|
+
|
|
150
|
+
if self.parsed.proxy:
|
|
151
|
+
args_preset.core.merge_custom({"web": {"http_proxy": self.parsed.proxy}})
|
|
148
152
|
|
|
149
153
|
if self.parsed.custom_headers:
|
|
150
154
|
args_preset.core.merge_custom({"web": {"http_headers": self.parsed.custom_headers}})
|
|
@@ -162,13 +166,17 @@ class BBOTArgs:
|
|
|
162
166
|
except Exception as e:
|
|
163
167
|
raise BBOTArgumentError(f'Error parsing command-line config option: "{config_arg}": {e}')
|
|
164
168
|
|
|
169
|
+
# strict scope
|
|
170
|
+
if self.parsed.strict_scope:
|
|
171
|
+
args_preset.core.merge_custom({"scope": {"strict": True}})
|
|
172
|
+
|
|
165
173
|
return args_preset
|
|
166
174
|
|
|
167
175
|
def create_parser(self, *args, **kwargs):
|
|
168
176
|
kwargs.update(
|
|
169
|
-
|
|
170
|
-
description
|
|
171
|
-
|
|
177
|
+
{
|
|
178
|
+
"description": "Bighuge BLS OSINT Tool", "formatter_class": argparse.RawTextHelpFormatter, "epilog": self.epilog
|
|
179
|
+
}
|
|
172
180
|
)
|
|
173
181
|
p = argparse.ArgumentParser(*args, **kwargs)
|
|
174
182
|
|
|
@@ -206,7 +214,7 @@ class BBOTArgs:
|
|
|
206
214
|
metavar="CONFIG",
|
|
207
215
|
default=[],
|
|
208
216
|
)
|
|
209
|
-
presets.add_argument("-lp", "--list-presets", action="store_true", help=
|
|
217
|
+
presets.add_argument("-lp", "--list-presets", action="store_true", help="List available presets.")
|
|
210
218
|
|
|
211
219
|
modules = p.add_argument_group(title="Modules")
|
|
212
220
|
modules.add_argument(
|
|
@@ -214,31 +222,31 @@ class BBOTArgs:
|
|
|
214
222
|
"--modules",
|
|
215
223
|
nargs="+",
|
|
216
224
|
default=[],
|
|
217
|
-
help=f'Modules to enable. Choices: {",".join(self.preset.module_loader.scan_module_choices)}',
|
|
225
|
+
help=f'Modules to enable. Choices: {",".join(sorted(self.preset.module_loader.scan_module_choices))}',
|
|
218
226
|
metavar="MODULE",
|
|
219
227
|
)
|
|
220
|
-
modules.add_argument("-l", "--list-modules", action="store_true", help=
|
|
228
|
+
modules.add_argument("-l", "--list-modules", action="store_true", help="List available modules.")
|
|
221
229
|
modules.add_argument(
|
|
222
230
|
"-lmo", "--list-module-options", action="store_true", help="Show all module config options"
|
|
223
231
|
)
|
|
224
232
|
modules.add_argument(
|
|
225
|
-
"-em", "--exclude-modules", nargs="+", default=[], help=
|
|
233
|
+
"-em", "--exclude-modules", nargs="+", default=[], help="Exclude these modules.", metavar="MODULE"
|
|
226
234
|
)
|
|
227
235
|
modules.add_argument(
|
|
228
236
|
"-f",
|
|
229
237
|
"--flags",
|
|
230
238
|
nargs="+",
|
|
231
239
|
default=[],
|
|
232
|
-
help=f'Enable modules by flag. Choices: {",".join(self.preset.module_loader.flag_choices)}',
|
|
240
|
+
help=f'Enable modules by flag. Choices: {",".join(sorted(self.preset.module_loader.flag_choices))}',
|
|
233
241
|
metavar="FLAG",
|
|
234
242
|
)
|
|
235
|
-
modules.add_argument("-lf", "--list-flags", action="store_true", help=
|
|
243
|
+
modules.add_argument("-lf", "--list-flags", action="store_true", help="List available flags.")
|
|
236
244
|
modules.add_argument(
|
|
237
245
|
"-rf",
|
|
238
246
|
"--require-flags",
|
|
239
247
|
nargs="+",
|
|
240
248
|
default=[],
|
|
241
|
-
help=
|
|
249
|
+
help="Only enable modules with these flags (e.g. -rf passive)",
|
|
242
250
|
metavar="FLAG",
|
|
243
251
|
)
|
|
244
252
|
modules.add_argument(
|
|
@@ -246,7 +254,7 @@ class BBOTArgs:
|
|
|
246
254
|
"--exclude-flags",
|
|
247
255
|
nargs="+",
|
|
248
256
|
default=[],
|
|
249
|
-
help=
|
|
257
|
+
help="Disable modules with these flags. (e.g. -ef aggressive)",
|
|
250
258
|
metavar="FLAG",
|
|
251
259
|
)
|
|
252
260
|
modules.add_argument("--allow-deadly", action="store_true", help="Enable the use of highly aggressive modules")
|
|
@@ -262,7 +270,12 @@ class BBOTArgs:
|
|
|
262
270
|
help="Run scan even in the case of condition violations or failed module setups",
|
|
263
271
|
)
|
|
264
272
|
scan.add_argument("-y", "--yes", action="store_true", help="Skip scan confirmation prompt")
|
|
265
|
-
scan.add_argument(
|
|
273
|
+
scan.add_argument(
|
|
274
|
+
"--fast-mode",
|
|
275
|
+
action="store_true",
|
|
276
|
+
help="Scan only the provided targets as fast as possible, with no extra discovery",
|
|
277
|
+
)
|
|
278
|
+
scan.add_argument("--dry-run", action="store_true", help="Abort before executing scan")
|
|
266
279
|
scan.add_argument(
|
|
267
280
|
"--current-preset",
|
|
268
281
|
action="store_true",
|
|
@@ -286,7 +299,7 @@ class BBOTArgs:
|
|
|
286
299
|
"--output-modules",
|
|
287
300
|
nargs="+",
|
|
288
301
|
default=[],
|
|
289
|
-
help=f'Output module(s). Choices: {",".join(self.preset.module_loader.output_module_choices)}',
|
|
302
|
+
help=f'Output module(s). Choices: {",".join(sorted(self.preset.module_loader.output_module_choices))}',
|
|
290
303
|
metavar="MODULE",
|
|
291
304
|
)
|
|
292
305
|
output.add_argument("--json", "-j", action="store_true", help="Output scan data in JSON format")
|
|
@@ -307,6 +320,7 @@ class BBOTArgs:
|
|
|
307
320
|
|
|
308
321
|
misc = p.add_argument_group(title="Misc")
|
|
309
322
|
misc.add_argument("--version", action="store_true", help="show BBOT version and exit")
|
|
323
|
+
misc.add_argument("--proxy", help="Use this proxy for all HTTP requests", metavar="HTTP_PROXY")
|
|
310
324
|
misc.add_argument(
|
|
311
325
|
"-H",
|
|
312
326
|
"--custom-headers",
|
|
@@ -356,6 +370,10 @@ class BBOTArgs:
|
|
|
356
370
|
custom_headers_dict[k] = v
|
|
357
371
|
self.parsed.custom_headers = custom_headers_dict
|
|
358
372
|
|
|
373
|
+
# --fast-mode
|
|
374
|
+
if self.parsed.fast_mode:
|
|
375
|
+
self.parsed.preset += ["fast"]
|
|
376
|
+
|
|
359
377
|
def validate(self):
|
|
360
378
|
# validate config options
|
|
361
379
|
sentinel = object()
|
bbot/scanner/preset/environ.py
CHANGED
|
@@ -6,6 +6,9 @@ from pathlib import Path
|
|
|
6
6
|
from bbot.core.helpers.misc import cpu_architecture, os_platform, os_platform_friendly
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
REQUESTS_PATCHED = False
|
|
10
|
+
|
|
11
|
+
|
|
9
12
|
def increase_limit(new_limit):
|
|
10
13
|
try:
|
|
11
14
|
import resource
|
|
@@ -62,7 +65,6 @@ omegaconf.OmegaConf.register_new_resolver("env", env_resolver)
|
|
|
62
65
|
|
|
63
66
|
|
|
64
67
|
class BBOTEnviron:
|
|
65
|
-
|
|
66
68
|
def __init__(self, preset):
|
|
67
69
|
self.preset = preset
|
|
68
70
|
|
|
@@ -120,7 +122,10 @@ class BBOTEnviron:
|
|
|
120
122
|
|
|
121
123
|
urllib3.disable_warnings()
|
|
122
124
|
ssl_verify = self.preset.config.get("ssl_verify", False)
|
|
123
|
-
|
|
125
|
+
|
|
126
|
+
global REQUESTS_PATCHED
|
|
127
|
+
if not ssl_verify and not REQUESTS_PATCHED:
|
|
128
|
+
REQUESTS_PATCHED = True
|
|
124
129
|
import requests
|
|
125
130
|
import functools
|
|
126
131
|
|
bbot/scanner/preset/path.py
CHANGED
|
@@ -33,13 +33,16 @@ 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):
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
if file.is_file():
|
|
43
|
+
log.verbose(f'Found preset matching "{filename}" at {file}')
|
|
44
|
+
self.add_path(file.parent)
|
|
45
|
+
return file.resolve()
|
|
43
46
|
raise ValidationError(
|
|
44
47
|
f'Could not find preset at "{filename}" - file does not exist. Use -lp to list available presets'
|
|
45
48
|
)
|
bbot/scanner/preset/preset.py
CHANGED
|
@@ -17,7 +17,7 @@ from bbot.core.helpers.misc import make_table, mkdir, get_closest_match
|
|
|
17
17
|
log = logging.getLogger("bbot.presets")
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
_preset_cache =
|
|
20
|
+
_preset_cache = {}
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
# cache default presets to prevent having to reload from disk
|
|
@@ -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,9 @@ class Preset:
|
|
|
353
355
|
else:
|
|
354
356
|
self._whitelist.update(other._whitelist)
|
|
355
357
|
self._blacklist.update(other._blacklist)
|
|
356
|
-
|
|
358
|
+
|
|
359
|
+
# module dirs
|
|
360
|
+
self.module_dirs = self.module_dirs.union(other.module_dirs)
|
|
357
361
|
|
|
358
362
|
# log verbosity
|
|
359
363
|
if other.silent:
|
|
@@ -373,6 +377,9 @@ class Preset:
|
|
|
373
377
|
# misc
|
|
374
378
|
self.force_start = self.force_start | other.force_start
|
|
375
379
|
self._cli = self._cli | other._cli
|
|
380
|
+
# transfer args
|
|
381
|
+
if other._args is not None:
|
|
382
|
+
self._args = other._args
|
|
376
383
|
|
|
377
384
|
def bake(self, scan=None):
|
|
378
385
|
"""
|
|
@@ -436,7 +443,7 @@ class Preset:
|
|
|
436
443
|
|
|
437
444
|
# disable internal modules if requested
|
|
438
445
|
for internal_module in baked_preset.internal_modules:
|
|
439
|
-
if baked_preset.config.get(internal_module, True)
|
|
446
|
+
if baked_preset.config.get(internal_module, True) is False:
|
|
440
447
|
baked_preset.exclude_modules.add(internal_module)
|
|
441
448
|
|
|
442
449
|
# enable modules by flag
|
|
@@ -531,6 +538,14 @@ class Preset:
|
|
|
531
538
|
def web_config(self):
|
|
532
539
|
return self.core.config.get("web", {})
|
|
533
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
|
+
|
|
534
549
|
def apply_log_level(self, apply_core=False):
|
|
535
550
|
# silent takes precedence
|
|
536
551
|
if self.silent:
|
|
@@ -629,7 +644,6 @@ class Preset:
|
|
|
629
644
|
debug=preset_dict.get("debug", False),
|
|
630
645
|
silent=preset_dict.get("silent", False),
|
|
631
646
|
config=preset_dict.get("config"),
|
|
632
|
-
strict_scope=preset_dict.get("strict_scope", False),
|
|
633
647
|
module_dirs=preset_dict.get("module_dirs", []),
|
|
634
648
|
include=list(preset_dict.get("include", [])),
|
|
635
649
|
scan_name=preset_dict.get("scan_name"),
|
|
@@ -731,6 +745,9 @@ class Preset:
|
|
|
731
745
|
"""
|
|
732
746
|
preset_dict = {}
|
|
733
747
|
|
|
748
|
+
if self.description:
|
|
749
|
+
preset_dict["description"] = self.description
|
|
750
|
+
|
|
734
751
|
# config
|
|
735
752
|
if full_config:
|
|
736
753
|
config = self.core.config
|
|
@@ -744,19 +761,17 @@ class Preset:
|
|
|
744
761
|
|
|
745
762
|
# scope
|
|
746
763
|
if include_target:
|
|
747
|
-
target = sorted(
|
|
764
|
+
target = sorted(self.target.seeds.inputs)
|
|
748
765
|
whitelist = []
|
|
749
766
|
if self.target.whitelist is not None:
|
|
750
|
-
whitelist = sorted(
|
|
751
|
-
blacklist = sorted(
|
|
767
|
+
whitelist = sorted(self.target.whitelist.inputs)
|
|
768
|
+
blacklist = sorted(self.target.blacklist.inputs)
|
|
752
769
|
if target:
|
|
753
770
|
preset_dict["target"] = target
|
|
754
771
|
if whitelist and whitelist != target:
|
|
755
772
|
preset_dict["whitelist"] = whitelist
|
|
756
773
|
if blacklist:
|
|
757
774
|
preset_dict["blacklist"] = blacklist
|
|
758
|
-
if self.strict_scope:
|
|
759
|
-
preset_dict["strict_scope"] = True
|
|
760
775
|
|
|
761
776
|
# flags + modules
|
|
762
777
|
if self.require_flags:
|
|
@@ -825,7 +840,7 @@ class Preset:
|
|
|
825
840
|
else:
|
|
826
841
|
raise ValidationError(f'Unknown module type "{module}"')
|
|
827
842
|
|
|
828
|
-
if not
|
|
843
|
+
if module not in module_choices:
|
|
829
844
|
raise ValidationError(get_closest_match(module, module_choices, msg=f"{module_type} module"))
|
|
830
845
|
|
|
831
846
|
try:
|
|
@@ -838,8 +853,6 @@ class Preset:
|
|
|
838
853
|
|
|
839
854
|
if module in self.exclude_modules:
|
|
840
855
|
reason = "the module has been excluded"
|
|
841
|
-
if raise_error:
|
|
842
|
-
raise ValidationError(f'Unable to add {module_type} module "{module}" because {reason}')
|
|
843
856
|
return False, reason, {}
|
|
844
857
|
|
|
845
858
|
module_flags = preloaded.get("flags", [])
|
|
@@ -870,21 +883,21 @@ class Preset:
|
|
|
870
883
|
|
|
871
884
|
# validate excluded modules
|
|
872
885
|
for excluded_module in self.exclude_modules:
|
|
873
|
-
if not
|
|
886
|
+
if excluded_module not in self.module_loader.all_module_choices:
|
|
874
887
|
raise ValidationError(
|
|
875
888
|
get_closest_match(excluded_module, self.module_loader.all_module_choices, msg="module")
|
|
876
889
|
)
|
|
877
890
|
# validate excluded flags
|
|
878
891
|
for excluded_flag in self.exclude_flags:
|
|
879
|
-
if not
|
|
892
|
+
if excluded_flag not in self.module_loader.flag_choices:
|
|
880
893
|
raise ValidationError(get_closest_match(excluded_flag, self.module_loader.flag_choices, msg="flag"))
|
|
881
894
|
# validate required flags
|
|
882
895
|
for required_flag in self.require_flags:
|
|
883
|
-
if not
|
|
896
|
+
if required_flag not in self.module_loader.flag_choices:
|
|
884
897
|
raise ValidationError(get_closest_match(required_flag, self.module_loader.flag_choices, msg="flag"))
|
|
885
898
|
# validate flags
|
|
886
899
|
for flag in self.flags:
|
|
887
|
-
if not
|
|
900
|
+
if flag not in self.module_loader.flag_choices:
|
|
888
901
|
raise ValidationError(get_closest_match(flag, self.module_loader.flag_choices, msg="flag"))
|
|
889
902
|
|
|
890
903
|
@property
|
|
@@ -903,7 +916,7 @@ class Preset:
|
|
|
903
916
|
|
|
904
917
|
global DEFAULT_PRESETS
|
|
905
918
|
if DEFAULT_PRESETS is None:
|
|
906
|
-
presets =
|
|
919
|
+
presets = {}
|
|
907
920
|
for ext in ("yml", "yaml"):
|
|
908
921
|
for preset_path in PRESET_PATH:
|
|
909
922
|
# for every yaml file
|
|
@@ -954,7 +967,7 @@ class Preset:
|
|
|
954
967
|
header = ["Preset", "Category", "Description", "# Modules"]
|
|
955
968
|
if include_modules:
|
|
956
969
|
header.append("Modules")
|
|
957
|
-
for
|
|
970
|
+
for (loaded_preset, category, preset_path, original_file) in self.all_presets.values():
|
|
958
971
|
loaded_preset = loaded_preset.bake()
|
|
959
972
|
num_modules = f"{len(loaded_preset.scan_modules):,}"
|
|
960
973
|
row = [loaded_preset.name, category, loaded_preset.description, num_modules]
|