bbot 2.0.1.4720rc0__py3-none-any.whl → 2.3.0.5401rc0__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 +12 -10
- 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 +20 -21
- 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 +29 -12
- bbot/modules/internal/dnsresolve.py +22 -22
- bbot/modules/internal/excavate.py +97 -59
- 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 +8 -11
- 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 +18 -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 -2
- bbot/presets/spider.yml +4 -0
- bbot/presets/subdomain-enum.yml +7 -7
- bbot/presets/web/dotnet-audit.yml +0 -1
- bbot/scanner/manager.py +5 -16
- bbot/scanner/preset/args.py +46 -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__module__tests.py +0 -1
- bbot/test/test_step_1/test_bbot_fastapi.py +79 -0
- bbot/test/test_step_1/test_bloom_filter.py +2 -1
- bbot/test/test_step_1/test_cli.py +138 -64
- bbot/test/test_step_1/test_dns.py +61 -27
- bbot/test/test_step_1/test_engine.py +17 -19
- bbot/test/test_step_1/test_events.py +183 -30
- bbot/test/test_step_1/test_helpers.py +64 -29
- 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 +183 -100
- 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 +242 -145
- bbot/test/test_step_1/test_web.py +14 -10
- 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 +28 -48
- 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 -6
- 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 +16 -16
- bbot/test/test_step_2/module_tests/test_module_ntlm.py +8 -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_pgp.py +2 -2
- 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 +14 -14
- bbot/test/test_step_2/module_tests/test_module_social.py +11 -1
- bbot/test/test_step_2/module_tests/test_module_speculate.py +4 -8
- 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_viewdns.py +1 -1
- 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/wordlists/devops_mutations.txt +1 -1
- bbot/wordlists/ffuf_shortname_candidates.txt +1 -1
- bbot/wordlists/nameservers.txt +1 -1
- bbot/wordlists/paramminer_headers.txt +1 -1
- bbot/wordlists/paramminer_parameters.txt +1 -1
- bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt +1 -1
- bbot/wordlists/valid_url_schemes.txt +1 -1
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/METADATA +48 -18
- bbot-2.3.0.5401rc0.dist-info/RECORD +421 -0
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.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.5401rc0.dist-info}/LICENSE +0 -0
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/entry_points.txt +0 -0
|
@@ -16,7 +16,7 @@ from bbot.scanner import Scanner, Preset
|
|
|
16
16
|
def test_preset_descriptions():
|
|
17
17
|
# ensure very preset has a description
|
|
18
18
|
preset = Preset()
|
|
19
|
-
for
|
|
19
|
+
for loaded_preset, category, preset_path, original_filename in preset.all_presets.values():
|
|
20
20
|
assert (
|
|
21
21
|
loaded_preset.description
|
|
22
22
|
), f'Preset "{loaded_preset.name}" at {original_filename} does not have a description.'
|
|
@@ -68,7 +68,6 @@ def test_core():
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
def test_preset_yaml(clean_default_config):
|
|
71
|
-
|
|
72
71
|
import yaml
|
|
73
72
|
|
|
74
73
|
preset1 = Preset(
|
|
@@ -86,12 +85,15 @@ def test_preset_yaml(clean_default_config):
|
|
|
86
85
|
debug=False,
|
|
87
86
|
silent=True,
|
|
88
87
|
config={"preset_test_asdf": 1},
|
|
89
|
-
strict_scope=False,
|
|
90
88
|
)
|
|
91
89
|
preset1 = preset1.bake()
|
|
92
|
-
assert "evilcorp.com" in preset1.target
|
|
90
|
+
assert "evilcorp.com" in preset1.target.seeds
|
|
91
|
+
assert "evilcorp.ce" not in preset1.target.seeds
|
|
92
|
+
assert "asdf.www.evilcorp.ce" in preset1.target.seeds
|
|
93
93
|
assert "evilcorp.ce" in preset1.whitelist
|
|
94
|
+
assert "asdf.evilcorp.ce" in preset1.whitelist
|
|
94
95
|
assert "test.www.evilcorp.ce" in preset1.blacklist
|
|
96
|
+
assert "asdf.test.www.evilcorp.ce" in preset1.blacklist
|
|
95
97
|
assert "sslcert" in preset1.scan_modules
|
|
96
98
|
assert preset1.whitelisted("evilcorp.ce")
|
|
97
99
|
assert preset1.whitelisted("www.evilcorp.ce")
|
|
@@ -168,11 +170,17 @@ exclude_flags:
|
|
|
168
170
|
|
|
169
171
|
|
|
170
172
|
def test_preset_scope():
|
|
173
|
+
# test target merging
|
|
174
|
+
scan = Scanner("1.2.3.4", preset=Preset.from_dict({"target": ["evilcorp.com"]}))
|
|
175
|
+
assert {str(h) for h in scan.preset.target.seeds.hosts} == {"1.2.3.4/32", "evilcorp.com"}
|
|
176
|
+
assert {e.data for e in scan.target.seeds} == {"1.2.3.4", "evilcorp.com"}
|
|
177
|
+
assert {e.data for e in scan.target.whitelist} == {"1.2.3.4", "evilcorp.com"}
|
|
171
178
|
|
|
172
179
|
blank_preset = Preset()
|
|
173
180
|
blank_preset = blank_preset.bake()
|
|
174
|
-
assert not blank_preset.target
|
|
175
|
-
assert blank_preset.
|
|
181
|
+
assert not blank_preset.target.seeds
|
|
182
|
+
assert not blank_preset.target.whitelist
|
|
183
|
+
assert blank_preset.strict_scope is False
|
|
176
184
|
|
|
177
185
|
preset1 = Preset(
|
|
178
186
|
"evilcorp.com",
|
|
@@ -183,13 +191,14 @@ def test_preset_scope():
|
|
|
183
191
|
preset1_baked = preset1.bake()
|
|
184
192
|
|
|
185
193
|
# make sure target logic works as expected
|
|
186
|
-
assert "evilcorp.com" in preset1_baked.target
|
|
187
|
-
assert "
|
|
188
|
-
assert "asdf.
|
|
189
|
-
assert
|
|
194
|
+
assert "evilcorp.com" in preset1_baked.target.seeds
|
|
195
|
+
assert "evilcorp.com" not in preset1_baked.target.whitelist
|
|
196
|
+
assert "asdf.evilcorp.com" in preset1_baked.target.seeds
|
|
197
|
+
assert "asdf.evilcorp.com" not in preset1_baked.target.whitelist
|
|
198
|
+
assert "asdf.evilcorp.ce" in preset1_baked.whitelist
|
|
190
199
|
assert "evilcorp.ce" in preset1_baked.whitelist
|
|
191
200
|
assert "test.www.evilcorp.ce" in preset1_baked.blacklist
|
|
192
|
-
assert
|
|
201
|
+
assert "evilcorp.ce" not in preset1_baked.blacklist
|
|
193
202
|
assert preset1_baked.in_scope("www.evilcorp.ce")
|
|
194
203
|
assert not preset1_baked.in_scope("evilcorp.com")
|
|
195
204
|
assert not preset1_baked.in_scope("asdf.test.www.evilcorp.ce")
|
|
@@ -205,7 +214,7 @@ def test_preset_scope():
|
|
|
205
214
|
"evilcorp.org",
|
|
206
215
|
whitelist=["evilcorp.de"],
|
|
207
216
|
blacklist=["test.www.evilcorp.de"],
|
|
208
|
-
|
|
217
|
+
config={"scope": {"strict": True}},
|
|
209
218
|
)
|
|
210
219
|
|
|
211
220
|
preset1.merge(preset3)
|
|
@@ -213,20 +222,24 @@ def test_preset_scope():
|
|
|
213
222
|
preset1_baked = preset1.bake()
|
|
214
223
|
|
|
215
224
|
# targets should be merged
|
|
216
|
-
assert "evilcorp.com" in preset1_baked.target
|
|
217
|
-
assert "www.evilcorp.ce" in preset1_baked.target
|
|
218
|
-
assert "evilcorp.org" in preset1_baked.target
|
|
225
|
+
assert "evilcorp.com" in preset1_baked.target.seeds
|
|
226
|
+
assert "www.evilcorp.ce" in preset1_baked.target.seeds
|
|
227
|
+
assert "evilcorp.org" in preset1_baked.target.seeds
|
|
219
228
|
# strict scope is enabled
|
|
220
|
-
assert
|
|
221
|
-
assert
|
|
229
|
+
assert "asdf.www.evilcorp.ce" not in preset1_baked.target.seeds
|
|
230
|
+
assert "asdf.evilcorp.org" not in preset1_baked.target.seeds
|
|
231
|
+
assert "asdf.evilcorp.com" not in preset1_baked.target.seeds
|
|
232
|
+
assert "asdf.www.evilcorp.ce" not in preset1_baked.target.seeds
|
|
222
233
|
assert "evilcorp.ce" in preset1_baked.whitelist
|
|
223
234
|
assert "evilcorp.de" in preset1_baked.whitelist
|
|
224
|
-
assert
|
|
225
|
-
assert
|
|
235
|
+
assert "asdf.evilcorp.de" not in preset1_baked.whitelist
|
|
236
|
+
assert "asdf.evilcorp.ce" not in preset1_baked.whitelist
|
|
226
237
|
# blacklist should be merged, strict scope does not apply
|
|
238
|
+
assert "test.www.evilcorp.ce" in preset1_baked.blacklist
|
|
239
|
+
assert "test.www.evilcorp.de" in preset1_baked.blacklist
|
|
227
240
|
assert "asdf.test.www.evilcorp.ce" in preset1_baked.blacklist
|
|
228
241
|
assert "asdf.test.www.evilcorp.de" in preset1_baked.blacklist
|
|
229
|
-
assert
|
|
242
|
+
assert "asdf.test.www.evilcorp.org" not in preset1_baked.blacklist
|
|
230
243
|
# only the base domain of evilcorp.de should be in scope
|
|
231
244
|
assert not preset1_baked.in_scope("evilcorp.com")
|
|
232
245
|
assert not preset1_baked.in_scope("evilcorp.org")
|
|
@@ -259,14 +272,14 @@ def test_preset_scope():
|
|
|
259
272
|
}
|
|
260
273
|
assert preset_whitelist_baked.to_dict(include_target=True) == {
|
|
261
274
|
"target": ["evilcorp.org"],
|
|
262
|
-
"whitelist": ["1.2.3.0/24", "evilcorp.net"],
|
|
263
|
-
"blacklist": ["evilcorp.co.uk"],
|
|
275
|
+
"whitelist": ["1.2.3.0/24", "http://evilcorp.net/"],
|
|
276
|
+
"blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"],
|
|
264
277
|
"config": {"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}},
|
|
265
278
|
}
|
|
266
279
|
assert preset_whitelist_baked.to_dict(include_target=True, redact_secrets=True) == {
|
|
267
280
|
"target": ["evilcorp.org"],
|
|
268
|
-
"whitelist": ["1.2.3.0/24", "evilcorp.net"],
|
|
269
|
-
"blacklist": ["evilcorp.co.uk"],
|
|
281
|
+
"whitelist": ["1.2.3.0/24", "http://evilcorp.net/"],
|
|
282
|
+
"blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"],
|
|
270
283
|
"config": {"modules": {"secretsdb": {"otherthing": "asdf"}}},
|
|
271
284
|
}
|
|
272
285
|
|
|
@@ -274,7 +287,8 @@ def test_preset_scope():
|
|
|
274
287
|
assert not preset_nowhitelist_baked.in_scope("www.evilcorp.de")
|
|
275
288
|
assert not preset_nowhitelist_baked.in_scope("1.2.3.4/24")
|
|
276
289
|
|
|
277
|
-
assert "www.evilcorp.org" in preset_whitelist_baked.target
|
|
290
|
+
assert "www.evilcorp.org" in preset_whitelist_baked.target.seeds
|
|
291
|
+
assert "www.evilcorp.org" not in preset_whitelist_baked.target.whitelist
|
|
278
292
|
assert "1.2.3.4" in preset_whitelist_baked.whitelist
|
|
279
293
|
assert not preset_whitelist_baked.in_scope("www.evilcorp.org")
|
|
280
294
|
assert not preset_whitelist_baked.in_scope("www.evilcorp.de")
|
|
@@ -287,17 +301,17 @@ def test_preset_scope():
|
|
|
287
301
|
assert preset_whitelist_baked.whitelisted("1.2.3.4/28")
|
|
288
302
|
assert preset_whitelist_baked.whitelisted("1.2.3.4/24")
|
|
289
303
|
|
|
290
|
-
assert
|
|
291
|
-
assert
|
|
292
|
-
assert
|
|
293
|
-
assert
|
|
304
|
+
assert {e.data for e in preset_nowhitelist_baked.seeds} == {"evilcorp.com"}
|
|
305
|
+
assert {e.data for e in preset_nowhitelist_baked.whitelist} == {"evilcorp.com"}
|
|
306
|
+
assert {e.data for e in preset_whitelist_baked.seeds} == {"evilcorp.org"}
|
|
307
|
+
assert {e.data for e in preset_whitelist_baked.whitelist} == {"1.2.3.0/24", "http://evilcorp.net/"}
|
|
294
308
|
|
|
295
309
|
preset_nowhitelist.merge(preset_whitelist)
|
|
296
310
|
preset_nowhitelist_baked = preset_nowhitelist.bake()
|
|
297
|
-
assert
|
|
298
|
-
assert
|
|
299
|
-
assert "www.evilcorp.org" in preset_nowhitelist_baked.
|
|
300
|
-
assert "www.evilcorp.com" in preset_nowhitelist_baked.
|
|
311
|
+
assert {e.data for e in preset_nowhitelist_baked.seeds} == {"evilcorp.com", "evilcorp.org"}
|
|
312
|
+
assert {e.data for e in preset_nowhitelist_baked.whitelist} == {"1.2.3.0/24", "http://evilcorp.net/"}
|
|
313
|
+
assert "www.evilcorp.org" in preset_nowhitelist_baked.seeds
|
|
314
|
+
assert "www.evilcorp.com" in preset_nowhitelist_baked.seeds
|
|
301
315
|
assert "1.2.3.4" in preset_nowhitelist_baked.whitelist
|
|
302
316
|
assert not preset_nowhitelist_baked.in_scope("www.evilcorp.org")
|
|
303
317
|
assert not preset_nowhitelist_baked.in_scope("www.evilcorp.com")
|
|
@@ -309,10 +323,12 @@ def test_preset_scope():
|
|
|
309
323
|
preset_whitelist = Preset("evilcorp.org", whitelist=["1.2.3.4/24"])
|
|
310
324
|
preset_whitelist.merge(preset_nowhitelist)
|
|
311
325
|
preset_whitelist_baked = preset_whitelist.bake()
|
|
312
|
-
assert
|
|
313
|
-
assert
|
|
314
|
-
assert "www.evilcorp.org" in preset_whitelist_baked.
|
|
315
|
-
assert "www.evilcorp.com" in preset_whitelist_baked.
|
|
326
|
+
assert {e.data for e in preset_whitelist_baked.seeds} == {"evilcorp.com", "evilcorp.org"}
|
|
327
|
+
assert {e.data for e in preset_whitelist_baked.whitelist} == {"1.2.3.0/24"}
|
|
328
|
+
assert "www.evilcorp.org" in preset_whitelist_baked.seeds
|
|
329
|
+
assert "www.evilcorp.com" in preset_whitelist_baked.seeds
|
|
330
|
+
assert "www.evilcorp.org" not in preset_whitelist_baked.target.whitelist
|
|
331
|
+
assert "www.evilcorp.com" not in preset_whitelist_baked.target.whitelist
|
|
316
332
|
assert "1.2.3.4" in preset_whitelist_baked.whitelist
|
|
317
333
|
assert not preset_whitelist_baked.in_scope("www.evilcorp.org")
|
|
318
334
|
assert not preset_whitelist_baked.in_scope("www.evilcorp.com")
|
|
@@ -324,18 +340,18 @@ def test_preset_scope():
|
|
|
324
340
|
preset_nowhitelist2 = Preset("evilcorp.de")
|
|
325
341
|
preset_nowhitelist1_baked = preset_nowhitelist1.bake()
|
|
326
342
|
preset_nowhitelist2_baked = preset_nowhitelist2.bake()
|
|
327
|
-
assert
|
|
328
|
-
assert
|
|
329
|
-
assert
|
|
330
|
-
assert
|
|
343
|
+
assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com"}
|
|
344
|
+
assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.de"}
|
|
345
|
+
assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com"}
|
|
346
|
+
assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.de"}
|
|
331
347
|
preset_nowhitelist1.merge(preset_nowhitelist2)
|
|
332
348
|
preset_nowhitelist1_baked = preset_nowhitelist1.bake()
|
|
333
|
-
assert
|
|
334
|
-
assert
|
|
335
|
-
assert
|
|
336
|
-
assert
|
|
337
|
-
assert "www.evilcorp.com" in preset_nowhitelist1_baked.
|
|
338
|
-
assert "www.evilcorp.de" in preset_nowhitelist1_baked.
|
|
349
|
+
assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com", "evilcorp.de"}
|
|
350
|
+
assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.de"}
|
|
351
|
+
assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com", "evilcorp.de"}
|
|
352
|
+
assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.de"}
|
|
353
|
+
assert "www.evilcorp.com" in preset_nowhitelist1_baked.seeds
|
|
354
|
+
assert "www.evilcorp.de" in preset_nowhitelist1_baked.seeds
|
|
339
355
|
assert "www.evilcorp.com" in preset_nowhitelist1_baked.target.seeds
|
|
340
356
|
assert "www.evilcorp.de" in preset_nowhitelist1_baked.target.seeds
|
|
341
357
|
assert "www.evilcorp.com" in preset_nowhitelist1_baked.whitelist
|
|
@@ -352,15 +368,14 @@ def test_preset_scope():
|
|
|
352
368
|
preset_nowhitelist2.merge(preset_nowhitelist1)
|
|
353
369
|
preset_nowhitelist1_baked = preset_nowhitelist1.bake()
|
|
354
370
|
preset_nowhitelist2_baked = preset_nowhitelist2.bake()
|
|
355
|
-
assert
|
|
356
|
-
assert
|
|
357
|
-
assert
|
|
358
|
-
assert
|
|
371
|
+
assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com"}
|
|
372
|
+
assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.com", "evilcorp.de"}
|
|
373
|
+
assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com"}
|
|
374
|
+
assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.com", "evilcorp.de"}
|
|
359
375
|
|
|
360
376
|
|
|
361
377
|
@pytest.mark.asyncio
|
|
362
378
|
async def test_preset_logging():
|
|
363
|
-
|
|
364
379
|
scan = Scanner()
|
|
365
380
|
|
|
366
381
|
# test individual verbosity levels
|
|
@@ -369,30 +384,30 @@ async def test_preset_logging():
|
|
|
369
384
|
|
|
370
385
|
try:
|
|
371
386
|
silent_preset = Preset(silent=True)
|
|
372
|
-
assert silent_preset.silent
|
|
373
|
-
assert silent_preset.debug
|
|
374
|
-
assert silent_preset.verbose
|
|
387
|
+
assert silent_preset.silent is True
|
|
388
|
+
assert silent_preset.debug is False
|
|
389
|
+
assert silent_preset.verbose is False
|
|
375
390
|
assert original_log_level == CORE.logger.log_level
|
|
376
391
|
debug_preset = Preset(debug=True)
|
|
377
|
-
assert debug_preset.silent
|
|
378
|
-
assert debug_preset.debug
|
|
379
|
-
assert debug_preset.verbose
|
|
392
|
+
assert debug_preset.silent is False
|
|
393
|
+
assert debug_preset.debug is True
|
|
394
|
+
assert debug_preset.verbose is False
|
|
380
395
|
assert original_log_level == CORE.logger.log_level
|
|
381
396
|
verbose_preset = Preset(verbose=True)
|
|
382
|
-
assert verbose_preset.silent
|
|
383
|
-
assert verbose_preset.debug
|
|
384
|
-
assert verbose_preset.verbose
|
|
397
|
+
assert verbose_preset.silent is False
|
|
398
|
+
assert verbose_preset.debug is False
|
|
399
|
+
assert verbose_preset.verbose is True
|
|
385
400
|
assert original_log_level == CORE.logger.log_level
|
|
386
401
|
|
|
387
402
|
# test conflicting verbosity levels
|
|
388
403
|
silent_and_verbose = Preset(silent=True, verbose=True)
|
|
389
|
-
assert silent_and_verbose.silent
|
|
390
|
-
assert silent_and_verbose.debug
|
|
391
|
-
assert silent_and_verbose.verbose
|
|
404
|
+
assert silent_and_verbose.silent is True
|
|
405
|
+
assert silent_and_verbose.debug is False
|
|
406
|
+
assert silent_and_verbose.verbose is True
|
|
392
407
|
baked = silent_and_verbose.bake()
|
|
393
|
-
assert baked.silent
|
|
394
|
-
assert baked.debug
|
|
395
|
-
assert baked.verbose
|
|
408
|
+
assert baked.silent is True
|
|
409
|
+
assert baked.debug is False
|
|
410
|
+
assert baked.verbose is False
|
|
396
411
|
assert baked.core.logger.log_level == original_log_level
|
|
397
412
|
baked = silent_and_verbose.bake(scan=scan)
|
|
398
413
|
assert baked.core.logger.log_level == logging.CRITICAL
|
|
@@ -402,13 +417,13 @@ async def test_preset_logging():
|
|
|
402
417
|
assert CORE.logger.log_level == original_log_level
|
|
403
418
|
|
|
404
419
|
silent_and_debug = Preset(silent=True, debug=True)
|
|
405
|
-
assert silent_and_debug.silent
|
|
406
|
-
assert silent_and_debug.debug
|
|
407
|
-
assert silent_and_debug.verbose
|
|
420
|
+
assert silent_and_debug.silent is True
|
|
421
|
+
assert silent_and_debug.debug is True
|
|
422
|
+
assert silent_and_debug.verbose is False
|
|
408
423
|
baked = silent_and_debug.bake()
|
|
409
|
-
assert baked.silent
|
|
410
|
-
assert baked.debug
|
|
411
|
-
assert baked.verbose
|
|
424
|
+
assert baked.silent is True
|
|
425
|
+
assert baked.debug is False
|
|
426
|
+
assert baked.verbose is False
|
|
412
427
|
assert baked.core.logger.log_level == original_log_level
|
|
413
428
|
baked = silent_and_debug.bake(scan=scan)
|
|
414
429
|
assert baked.core.logger.log_level == logging.CRITICAL
|
|
@@ -418,13 +433,13 @@ async def test_preset_logging():
|
|
|
418
433
|
assert CORE.logger.log_level == original_log_level
|
|
419
434
|
|
|
420
435
|
debug_and_verbose = Preset(verbose=True, debug=True)
|
|
421
|
-
assert debug_and_verbose.silent
|
|
422
|
-
assert debug_and_verbose.debug
|
|
423
|
-
assert debug_and_verbose.verbose
|
|
436
|
+
assert debug_and_verbose.silent is False
|
|
437
|
+
assert debug_and_verbose.debug is True
|
|
438
|
+
assert debug_and_verbose.verbose is True
|
|
424
439
|
baked = debug_and_verbose.bake()
|
|
425
|
-
assert baked.silent
|
|
426
|
-
assert baked.debug
|
|
427
|
-
assert baked.verbose
|
|
440
|
+
assert baked.silent is False
|
|
441
|
+
assert baked.debug is True
|
|
442
|
+
assert baked.verbose is False
|
|
428
443
|
assert baked.core.logger.log_level == original_log_level
|
|
429
444
|
baked = debug_and_verbose.bake(scan=scan)
|
|
430
445
|
assert baked.core.logger.log_level == logging.DEBUG
|
|
@@ -434,13 +449,13 @@ async def test_preset_logging():
|
|
|
434
449
|
assert CORE.logger.log_level == original_log_level
|
|
435
450
|
|
|
436
451
|
all_preset = Preset(verbose=True, debug=True, silent=True)
|
|
437
|
-
assert all_preset.silent
|
|
438
|
-
assert all_preset.debug
|
|
439
|
-
assert all_preset.verbose
|
|
452
|
+
assert all_preset.silent is True
|
|
453
|
+
assert all_preset.debug is True
|
|
454
|
+
assert all_preset.verbose is True
|
|
440
455
|
baked = all_preset.bake()
|
|
441
|
-
assert baked.silent
|
|
442
|
-
assert baked.debug
|
|
443
|
-
assert baked.verbose
|
|
456
|
+
assert baked.silent is True
|
|
457
|
+
assert baked.debug is False
|
|
458
|
+
assert baked.verbose is False
|
|
444
459
|
assert baked.core.logger.log_level == original_log_level
|
|
445
460
|
baked = all_preset.bake(scan=scan)
|
|
446
461
|
assert baked.core.logger.log_level == logging.CRITICAL
|
|
@@ -527,12 +542,26 @@ def test_preset_module_resolution(clean_default_config):
|
|
|
527
542
|
assert set(preset.scan_modules) == {"wayback"}
|
|
528
543
|
|
|
529
544
|
# modules + module exclusions
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
assert
|
|
545
|
+
preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "wappalyzer", "wayback"]).bake()
|
|
546
|
+
baked_preset = preset.bake()
|
|
547
|
+
assert baked_preset.modules == {
|
|
548
|
+
"wayback",
|
|
549
|
+
"cloudcheck",
|
|
550
|
+
"python",
|
|
551
|
+
"json",
|
|
552
|
+
"speculate",
|
|
553
|
+
"dnsresolve",
|
|
554
|
+
"aggregate",
|
|
555
|
+
"excavate",
|
|
556
|
+
"txt",
|
|
557
|
+
"httpx",
|
|
558
|
+
"csv",
|
|
559
|
+
"wappalyzer",
|
|
560
|
+
}
|
|
533
561
|
|
|
534
562
|
|
|
535
|
-
|
|
563
|
+
@pytest.mark.asyncio
|
|
564
|
+
async def test_preset_module_loader():
|
|
536
565
|
custom_module_dir = bbot_test_dir / "custom_module_dir"
|
|
537
566
|
custom_module_dir_2 = custom_module_dir / "asdf"
|
|
538
567
|
custom_output_module_dir = custom_module_dir / "output"
|
|
@@ -640,9 +669,45 @@ class TestModule4(BaseModule):
|
|
|
640
669
|
# reset module_loader
|
|
641
670
|
preset2.module_loader.__init__()
|
|
642
671
|
|
|
672
|
+
# custom module dir via preset
|
|
673
|
+
custom_module_dir_3 = bbot_test_dir / "custom_module_dir_3"
|
|
674
|
+
custom_module_dir_3.mkdir(exist_ok=True, parents=True)
|
|
675
|
+
custom_module_5 = custom_module_dir_3 / "testmodule5.py"
|
|
676
|
+
with open(custom_module_5, "w") as f:
|
|
677
|
+
f.write(
|
|
678
|
+
"""
|
|
679
|
+
from bbot.modules.base import BaseModule
|
|
643
680
|
|
|
644
|
-
|
|
681
|
+
class TestModule5(BaseModule):
|
|
682
|
+
watched_events = ["TECHNOLOGY"]
|
|
683
|
+
produced_events = ["FINDING"]
|
|
684
|
+
"""
|
|
685
|
+
)
|
|
645
686
|
|
|
687
|
+
preset = Preset.from_yaml_string(
|
|
688
|
+
"""
|
|
689
|
+
modules:
|
|
690
|
+
- testmodule5
|
|
691
|
+
"""
|
|
692
|
+
)
|
|
693
|
+
# should fail
|
|
694
|
+
with pytest.raises(ValidationError):
|
|
695
|
+
scan = Scanner(preset=preset)
|
|
696
|
+
|
|
697
|
+
preset = Preset.from_yaml_string(
|
|
698
|
+
f"""
|
|
699
|
+
module_dirs:
|
|
700
|
+
- {custom_module_dir_3}
|
|
701
|
+
modules:
|
|
702
|
+
- testmodule5
|
|
703
|
+
"""
|
|
704
|
+
)
|
|
705
|
+
scan = Scanner(preset=preset)
|
|
706
|
+
await scan._prep()
|
|
707
|
+
assert "testmodule5" in scan.modules
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def test_preset_include():
|
|
646
711
|
# test recursive preset inclusion
|
|
647
712
|
|
|
648
713
|
custom_preset_dir_1 = bbot_test_dir / "custom_preset_dir"
|
|
@@ -814,7 +879,6 @@ def test_preset_module_disablement(clean_default_config):
|
|
|
814
879
|
|
|
815
880
|
|
|
816
881
|
def test_preset_require_exclude():
|
|
817
|
-
|
|
818
882
|
def get_module_flags(p):
|
|
819
883
|
for m in p.scan_modules:
|
|
820
884
|
preloaded = p.preloaded_module(m)
|
|
@@ -827,9 +891,9 @@ def test_preset_require_exclude():
|
|
|
827
891
|
dnsbrute_flags = preset.preloaded_module("dnsbrute").get("flags", [])
|
|
828
892
|
assert "subdomain-enum" in dnsbrute_flags
|
|
829
893
|
assert "active" in dnsbrute_flags
|
|
830
|
-
assert
|
|
894
|
+
assert "passive" not in dnsbrute_flags
|
|
831
895
|
assert "aggressive" in dnsbrute_flags
|
|
832
|
-
assert
|
|
896
|
+
assert "safe" not in dnsbrute_flags
|
|
833
897
|
assert "dnsbrute" in [x[0] for x in module_flags]
|
|
834
898
|
assert "certspotter" in [x[0] for x in module_flags]
|
|
835
899
|
assert "c99" in [x[0] for x in module_flags]
|
|
@@ -843,7 +907,7 @@ def test_preset_require_exclude():
|
|
|
843
907
|
assert len(preset.modules) > 25
|
|
844
908
|
module_flags = list(get_module_flags(preset))
|
|
845
909
|
assert "chaos" in [x[0] for x in module_flags]
|
|
846
|
-
assert
|
|
910
|
+
assert "httpx" not in [x[0] for x in module_flags]
|
|
847
911
|
assert all("passive" in flags for module, flags in module_flags)
|
|
848
912
|
assert not any("active" in flags for module, flags in module_flags)
|
|
849
913
|
assert any("safe" in flags for module, flags in module_flags)
|
|
@@ -854,7 +918,7 @@ def test_preset_require_exclude():
|
|
|
854
918
|
assert len(preset.modules) > 25
|
|
855
919
|
module_flags = list(get_module_flags(preset))
|
|
856
920
|
assert "chaos" in [x[0] for x in module_flags]
|
|
857
|
-
assert
|
|
921
|
+
assert "httpx" not in [x[0] for x in module_flags]
|
|
858
922
|
assert all("passive" in flags for module, flags in module_flags)
|
|
859
923
|
assert not any("active" in flags for module, flags in module_flags)
|
|
860
924
|
assert any("safe" in flags for module, flags in module_flags)
|
|
@@ -864,7 +928,7 @@ def test_preset_require_exclude():
|
|
|
864
928
|
preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute"]).bake()
|
|
865
929
|
assert len(preset.modules) > 25
|
|
866
930
|
module_flags = list(get_module_flags(preset))
|
|
867
|
-
assert
|
|
931
|
+
assert "dnsbrute" not in [x[0] for x in module_flags]
|
|
868
932
|
assert "httpx" in [x[0] for x in module_flags]
|
|
869
933
|
assert any("passive" in flags for module, flags in module_flags)
|
|
870
934
|
assert any("active" in flags for module, flags in module_flags)
|
|
@@ -875,7 +939,7 @@ def test_preset_require_exclude():
|
|
|
875
939
|
preset = Preset(flags=["subdomain-enum"], require_flags=["safe", "passive"]).bake()
|
|
876
940
|
assert len(preset.modules) > 25
|
|
877
941
|
module_flags = list(get_module_flags(preset))
|
|
878
|
-
assert
|
|
942
|
+
assert "dnsbrute" not in [x[0] for x in module_flags]
|
|
879
943
|
assert all("passive" in flags and "safe" in flags for module, flags in module_flags)
|
|
880
944
|
assert all("active" not in flags and "aggressive" not in flags for module, flags in module_flags)
|
|
881
945
|
assert not any("active" in flags for module, flags in module_flags)
|
|
@@ -885,7 +949,7 @@ def test_preset_require_exclude():
|
|
|
885
949
|
preset = Preset(flags=["subdomain-enum"], exclude_flags=["aggressive", "active"]).bake()
|
|
886
950
|
assert len(preset.modules) > 25
|
|
887
951
|
module_flags = list(get_module_flags(preset))
|
|
888
|
-
assert
|
|
952
|
+
assert "dnsbrute" not in [x[0] for x in module_flags]
|
|
889
953
|
assert all("passive" in flags and "safe" in flags for module, flags in module_flags)
|
|
890
954
|
assert all("active" not in flags and "aggressive" not in flags for module, flags in module_flags)
|
|
891
955
|
assert not any("active" in flags for module, flags in module_flags)
|
|
@@ -895,10 +959,29 @@ def test_preset_require_exclude():
|
|
|
895
959
|
preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute", "c99"]).bake()
|
|
896
960
|
assert len(preset.modules) > 25
|
|
897
961
|
module_flags = list(get_module_flags(preset))
|
|
898
|
-
assert
|
|
962
|
+
assert "dnsbrute" not in [x[0] for x in module_flags]
|
|
899
963
|
assert "certspotter" in [x[0] for x in module_flags]
|
|
900
|
-
assert
|
|
964
|
+
assert "c99" not in [x[0] for x in module_flags]
|
|
901
965
|
assert any("passive" in flags for module, flags in module_flags)
|
|
902
966
|
assert any("active" in flags for module, flags in module_flags)
|
|
903
967
|
assert any("safe" in flags for module, flags in module_flags)
|
|
904
968
|
assert any("aggressive" in flags for module, flags in module_flags)
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
@pytest.mark.asyncio
|
|
972
|
+
async def test_preset_output_dir():
|
|
973
|
+
output_dir = bbot_test_dir / "preset_output_dir"
|
|
974
|
+
preset = Preset.from_yaml_string(
|
|
975
|
+
f"""
|
|
976
|
+
output_dir: {output_dir}
|
|
977
|
+
scan_name: bbot_test
|
|
978
|
+
"""
|
|
979
|
+
)
|
|
980
|
+
scan = Scanner(preset=preset)
|
|
981
|
+
await scan.async_start_without_generator()
|
|
982
|
+
scan_dir = output_dir / "bbot_test"
|
|
983
|
+
assert scan_dir.is_dir()
|
|
984
|
+
output_file = scan_dir / "output.txt"
|
|
985
|
+
assert output_file.is_file()
|
|
986
|
+
|
|
987
|
+
shutil.rmtree(output_dir, ignore_errors=True)
|
|
@@ -84,6 +84,10 @@ def test_python_api_sync():
|
|
|
84
84
|
def test_python_api_validation():
|
|
85
85
|
from bbot.scanner import Scanner, Preset
|
|
86
86
|
|
|
87
|
+
# invalid target
|
|
88
|
+
with pytest.raises(ValidationError) as error:
|
|
89
|
+
Scanner("asdf:::asdf")
|
|
90
|
+
assert str(error.value) == 'Unable to autodetect event type from "asdf:::asdf"'
|
|
87
91
|
# invalid module
|
|
88
92
|
with pytest.raises(ValidationError) as error:
|
|
89
93
|
Scanner(modules=["asdf"])
|
|
@@ -122,7 +126,8 @@ def test_python_api_validation():
|
|
|
122
126
|
assert str(error.value) == 'Preset must be of type Preset, not "str"'
|
|
123
127
|
# include nonexistent preset
|
|
124
128
|
with pytest.raises(ValidationError) as error:
|
|
125
|
-
Preset(include=["
|
|
129
|
+
Preset(include=["nonexistent"])
|
|
126
130
|
assert (
|
|
127
|
-
str(error.value)
|
|
131
|
+
str(error.value)
|
|
132
|
+
== 'Could not find preset at "nonexistent" - file does not exist. Use -lp to list available presets'
|
|
128
133
|
)
|
|
@@ -91,7 +91,7 @@ def test_ip_regexes():
|
|
|
91
91
|
ip == "2001:db8::1/128" and event_type == "IP_RANGE"
|
|
92
92
|
), f"Event type for IP_ADDRESS {ip} was not properly detected"
|
|
93
93
|
else:
|
|
94
|
-
matches =
|
|
94
|
+
matches = [r.match(ip) for r in ip_address_regexes]
|
|
95
95
|
assert any(matches), f"Good IP ADDRESS {ip} did not match regexes"
|
|
96
96
|
|
|
97
97
|
|
|
@@ -138,7 +138,7 @@ def test_ip_range_regexes():
|
|
|
138
138
|
pytest.fail(f"BAD IP_RANGE: {bad_ip_range} raised unknown error: {e}: {traceback.format_exc()}")
|
|
139
139
|
|
|
140
140
|
for good_ip_range in good_ip_ranges:
|
|
141
|
-
matches =
|
|
141
|
+
matches = [r.match(good_ip_range) for r in ip_range_regexes]
|
|
142
142
|
assert any(matches), f"Good IP_RANGE {good_ip_range} did not match regexes"
|
|
143
143
|
|
|
144
144
|
|
|
@@ -191,7 +191,7 @@ def test_dns_name_regexes():
|
|
|
191
191
|
pytest.fail(f"BAD DNS NAME: {dns} raised unknown error: {e}")
|
|
192
192
|
|
|
193
193
|
for dns in good_dns:
|
|
194
|
-
matches =
|
|
194
|
+
matches = [r.match(dns) for r in dns_name_regexes]
|
|
195
195
|
assert any(matches), f"Good DNS_NAME {dns} did not match regexes"
|
|
196
196
|
event_type, _ = get_event_type(dns)
|
|
197
197
|
if not event_type == "DNS_NAME":
|
|
@@ -253,7 +253,7 @@ def test_open_port_regexes():
|
|
|
253
253
|
pytest.fail(f"BAD OPEN_TCP_PORT: {open_port} raised unknown error: {e}")
|
|
254
254
|
|
|
255
255
|
for open_port in good_ports:
|
|
256
|
-
matches =
|
|
256
|
+
matches = [r.match(open_port) for r in open_port_regexes]
|
|
257
257
|
assert any(matches), f"Good OPEN_TCP_PORT {open_port} did not match regexes"
|
|
258
258
|
event_type, _ = get_event_type(open_port)
|
|
259
259
|
assert event_type == "OPEN_TCP_PORT"
|
|
@@ -318,7 +318,7 @@ def test_url_regexes():
|
|
|
318
318
|
pytest.fail(f"BAD URL: {bad_url} raised unknown error: {e}: {traceback.format_exc()}")
|
|
319
319
|
|
|
320
320
|
for good_url in good_urls:
|
|
321
|
-
matches =
|
|
321
|
+
matches = [r.match(good_url) for r in url_regexes]
|
|
322
322
|
assert any(matches), f"Good URL {good_url} did not match regexes"
|
|
323
323
|
assert (
|
|
324
324
|
get_event_type(good_url)[0] == "URL_UNVERIFIED"
|
|
@@ -372,3 +372,33 @@ async def test_regex_helper():
|
|
|
372
372
|
assert matches.count(s) == 2
|
|
373
373
|
|
|
374
374
|
await scan._cleanup()
|
|
375
|
+
|
|
376
|
+
# test yara hostname extractor helper
|
|
377
|
+
scan = Scanner("evilcorp.com", "www.evilcorp.net", "evilcorp.co.uk")
|
|
378
|
+
host_blob = """
|
|
379
|
+
https://evilcorp.com/
|
|
380
|
+
https://asdf.evilcorp.com/
|
|
381
|
+
https://asdf.www.evilcorp.net/
|
|
382
|
+
https://asdf.www.evilcorp.co.uk/
|
|
383
|
+
https://asdf.www.evilcorp.com/
|
|
384
|
+
https://asdf.www.evilcorp.com/
|
|
385
|
+
https://test.api.www.evilcorp.net/
|
|
386
|
+
"""
|
|
387
|
+
extracted = await scan.extract_in_scope_hostnames(host_blob)
|
|
388
|
+
assert extracted == {
|
|
389
|
+
"evilcorp.co.uk",
|
|
390
|
+
"evilcorp.com",
|
|
391
|
+
"www.evilcorp.com",
|
|
392
|
+
"asdf.evilcorp.com",
|
|
393
|
+
"asdf.www.evilcorp.com",
|
|
394
|
+
"www.evilcorp.net",
|
|
395
|
+
"api.www.evilcorp.net",
|
|
396
|
+
"asdf.www.evilcorp.net",
|
|
397
|
+
"test.api.www.evilcorp.net",
|
|
398
|
+
"asdf.www.evilcorp.co.uk",
|
|
399
|
+
"www.evilcorp.co.uk",
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
scan = Scanner()
|
|
403
|
+
extracted = await scan.extract_in_scope_hostnames(host_blob)
|
|
404
|
+
assert extracted == set()
|