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
|
@@ -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.'
|
|
@@ -86,12 +86,15 @@ def test_preset_yaml(clean_default_config):
|
|
|
86
86
|
debug=False,
|
|
87
87
|
silent=True,
|
|
88
88
|
config={"preset_test_asdf": 1},
|
|
89
|
-
strict_scope=False,
|
|
90
89
|
)
|
|
91
90
|
preset1 = preset1.bake()
|
|
92
|
-
assert "evilcorp.com" in preset1.target
|
|
91
|
+
assert "evilcorp.com" in preset1.target.seeds
|
|
92
|
+
assert "evilcorp.ce" not in preset1.target.seeds
|
|
93
|
+
assert "asdf.www.evilcorp.ce" in preset1.target.seeds
|
|
93
94
|
assert "evilcorp.ce" in preset1.whitelist
|
|
95
|
+
assert "asdf.evilcorp.ce" in preset1.whitelist
|
|
94
96
|
assert "test.www.evilcorp.ce" in preset1.blacklist
|
|
97
|
+
assert "asdf.test.www.evilcorp.ce" in preset1.blacklist
|
|
95
98
|
assert "sslcert" in preset1.scan_modules
|
|
96
99
|
assert preset1.whitelisted("evilcorp.ce")
|
|
97
100
|
assert preset1.whitelisted("www.evilcorp.ce")
|
|
@@ -169,10 +172,17 @@ exclude_flags:
|
|
|
169
172
|
|
|
170
173
|
def test_preset_scope():
|
|
171
174
|
|
|
175
|
+
# test target merging
|
|
176
|
+
scan = Scanner("1.2.3.4", preset=Preset.from_dict({"target": ["evilcorp.com"]}))
|
|
177
|
+
assert {str(h) for h in scan.preset.target.seeds.hosts} == {"1.2.3.4/32", "evilcorp.com"}
|
|
178
|
+
assert {e.data for e in scan.target.seeds} == {"1.2.3.4", "evilcorp.com"}
|
|
179
|
+
assert {e.data for e in scan.target.whitelist} == {"1.2.3.4", "evilcorp.com"}
|
|
180
|
+
|
|
172
181
|
blank_preset = Preset()
|
|
173
182
|
blank_preset = blank_preset.bake()
|
|
174
|
-
assert not blank_preset.target
|
|
175
|
-
assert blank_preset.
|
|
183
|
+
assert not blank_preset.target.seeds
|
|
184
|
+
assert not blank_preset.target.whitelist
|
|
185
|
+
assert blank_preset.strict_scope is False
|
|
176
186
|
|
|
177
187
|
preset1 = Preset(
|
|
178
188
|
"evilcorp.com",
|
|
@@ -183,13 +193,14 @@ def test_preset_scope():
|
|
|
183
193
|
preset1_baked = preset1.bake()
|
|
184
194
|
|
|
185
195
|
# make sure target logic works as expected
|
|
186
|
-
assert "evilcorp.com" in preset1_baked.target
|
|
187
|
-
assert "
|
|
188
|
-
assert "asdf.
|
|
189
|
-
assert
|
|
196
|
+
assert "evilcorp.com" in preset1_baked.target.seeds
|
|
197
|
+
assert "evilcorp.com" not in preset1_baked.target.whitelist
|
|
198
|
+
assert "asdf.evilcorp.com" in preset1_baked.target.seeds
|
|
199
|
+
assert "asdf.evilcorp.com" not in preset1_baked.target.whitelist
|
|
200
|
+
assert "asdf.evilcorp.ce" in preset1_baked.whitelist
|
|
190
201
|
assert "evilcorp.ce" in preset1_baked.whitelist
|
|
191
202
|
assert "test.www.evilcorp.ce" in preset1_baked.blacklist
|
|
192
|
-
assert
|
|
203
|
+
assert "evilcorp.ce" not in preset1_baked.blacklist
|
|
193
204
|
assert preset1_baked.in_scope("www.evilcorp.ce")
|
|
194
205
|
assert not preset1_baked.in_scope("evilcorp.com")
|
|
195
206
|
assert not preset1_baked.in_scope("asdf.test.www.evilcorp.ce")
|
|
@@ -205,7 +216,7 @@ def test_preset_scope():
|
|
|
205
216
|
"evilcorp.org",
|
|
206
217
|
whitelist=["evilcorp.de"],
|
|
207
218
|
blacklist=["test.www.evilcorp.de"],
|
|
208
|
-
|
|
219
|
+
config={"scope": {"strict": True}},
|
|
209
220
|
)
|
|
210
221
|
|
|
211
222
|
preset1.merge(preset3)
|
|
@@ -213,20 +224,24 @@ def test_preset_scope():
|
|
|
213
224
|
preset1_baked = preset1.bake()
|
|
214
225
|
|
|
215
226
|
# 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
|
|
227
|
+
assert "evilcorp.com" in preset1_baked.target.seeds
|
|
228
|
+
assert "www.evilcorp.ce" in preset1_baked.target.seeds
|
|
229
|
+
assert "evilcorp.org" in preset1_baked.target.seeds
|
|
219
230
|
# strict scope is enabled
|
|
220
|
-
assert
|
|
221
|
-
assert
|
|
231
|
+
assert "asdf.www.evilcorp.ce" not in preset1_baked.target.seeds
|
|
232
|
+
assert "asdf.evilcorp.org" not in preset1_baked.target.seeds
|
|
233
|
+
assert "asdf.evilcorp.com" not in preset1_baked.target.seeds
|
|
234
|
+
assert "asdf.www.evilcorp.ce" not in preset1_baked.target.seeds
|
|
222
235
|
assert "evilcorp.ce" in preset1_baked.whitelist
|
|
223
236
|
assert "evilcorp.de" in preset1_baked.whitelist
|
|
224
|
-
assert
|
|
225
|
-
assert
|
|
237
|
+
assert "asdf.evilcorp.de" not in preset1_baked.whitelist
|
|
238
|
+
assert "asdf.evilcorp.ce" not in preset1_baked.whitelist
|
|
226
239
|
# blacklist should be merged, strict scope does not apply
|
|
240
|
+
assert "test.www.evilcorp.ce" in preset1_baked.blacklist
|
|
241
|
+
assert "test.www.evilcorp.de" in preset1_baked.blacklist
|
|
227
242
|
assert "asdf.test.www.evilcorp.ce" in preset1_baked.blacklist
|
|
228
243
|
assert "asdf.test.www.evilcorp.de" in preset1_baked.blacklist
|
|
229
|
-
assert
|
|
244
|
+
assert "asdf.test.www.evilcorp.org" not in preset1_baked.blacklist
|
|
230
245
|
# only the base domain of evilcorp.de should be in scope
|
|
231
246
|
assert not preset1_baked.in_scope("evilcorp.com")
|
|
232
247
|
assert not preset1_baked.in_scope("evilcorp.org")
|
|
@@ -259,14 +274,14 @@ def test_preset_scope():
|
|
|
259
274
|
}
|
|
260
275
|
assert preset_whitelist_baked.to_dict(include_target=True) == {
|
|
261
276
|
"target": ["evilcorp.org"],
|
|
262
|
-
"whitelist": ["1.2.3.0/24", "evilcorp.net"],
|
|
263
|
-
"blacklist": ["evilcorp.co.uk"],
|
|
277
|
+
"whitelist": ["1.2.3.0/24", "http://evilcorp.net/"],
|
|
278
|
+
"blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"],
|
|
264
279
|
"config": {"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}},
|
|
265
280
|
}
|
|
266
281
|
assert preset_whitelist_baked.to_dict(include_target=True, redact_secrets=True) == {
|
|
267
282
|
"target": ["evilcorp.org"],
|
|
268
|
-
"whitelist": ["1.2.3.0/24", "evilcorp.net"],
|
|
269
|
-
"blacklist": ["evilcorp.co.uk"],
|
|
283
|
+
"whitelist": ["1.2.3.0/24", "http://evilcorp.net/"],
|
|
284
|
+
"blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"],
|
|
270
285
|
"config": {"modules": {"secretsdb": {"otherthing": "asdf"}}},
|
|
271
286
|
}
|
|
272
287
|
|
|
@@ -274,7 +289,8 @@ def test_preset_scope():
|
|
|
274
289
|
assert not preset_nowhitelist_baked.in_scope("www.evilcorp.de")
|
|
275
290
|
assert not preset_nowhitelist_baked.in_scope("1.2.3.4/24")
|
|
276
291
|
|
|
277
|
-
assert "www.evilcorp.org" in preset_whitelist_baked.target
|
|
292
|
+
assert "www.evilcorp.org" in preset_whitelist_baked.target.seeds
|
|
293
|
+
assert "www.evilcorp.org" not in preset_whitelist_baked.target.whitelist
|
|
278
294
|
assert "1.2.3.4" in preset_whitelist_baked.whitelist
|
|
279
295
|
assert not preset_whitelist_baked.in_scope("www.evilcorp.org")
|
|
280
296
|
assert not preset_whitelist_baked.in_scope("www.evilcorp.de")
|
|
@@ -287,17 +303,17 @@ def test_preset_scope():
|
|
|
287
303
|
assert preset_whitelist_baked.whitelisted("1.2.3.4/28")
|
|
288
304
|
assert preset_whitelist_baked.whitelisted("1.2.3.4/24")
|
|
289
305
|
|
|
290
|
-
assert
|
|
291
|
-
assert
|
|
292
|
-
assert
|
|
293
|
-
assert
|
|
306
|
+
assert {e.data for e in preset_nowhitelist_baked.seeds} == {"evilcorp.com"}
|
|
307
|
+
assert {e.data for e in preset_nowhitelist_baked.whitelist} == {"evilcorp.com"}
|
|
308
|
+
assert {e.data for e in preset_whitelist_baked.seeds} == {"evilcorp.org"}
|
|
309
|
+
assert {e.data for e in preset_whitelist_baked.whitelist} == {"1.2.3.0/24", "http://evilcorp.net/"}
|
|
294
310
|
|
|
295
311
|
preset_nowhitelist.merge(preset_whitelist)
|
|
296
312
|
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.
|
|
313
|
+
assert {e.data for e in preset_nowhitelist_baked.seeds} == {"evilcorp.com", "evilcorp.org"}
|
|
314
|
+
assert {e.data for e in preset_nowhitelist_baked.whitelist} == {"1.2.3.0/24", "http://evilcorp.net/"}
|
|
315
|
+
assert "www.evilcorp.org" in preset_nowhitelist_baked.seeds
|
|
316
|
+
assert "www.evilcorp.com" in preset_nowhitelist_baked.seeds
|
|
301
317
|
assert "1.2.3.4" in preset_nowhitelist_baked.whitelist
|
|
302
318
|
assert not preset_nowhitelist_baked.in_scope("www.evilcorp.org")
|
|
303
319
|
assert not preset_nowhitelist_baked.in_scope("www.evilcorp.com")
|
|
@@ -309,10 +325,12 @@ def test_preset_scope():
|
|
|
309
325
|
preset_whitelist = Preset("evilcorp.org", whitelist=["1.2.3.4/24"])
|
|
310
326
|
preset_whitelist.merge(preset_nowhitelist)
|
|
311
327
|
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.
|
|
328
|
+
assert {e.data for e in preset_whitelist_baked.seeds} == {"evilcorp.com", "evilcorp.org"}
|
|
329
|
+
assert {e.data for e in preset_whitelist_baked.whitelist} == {"1.2.3.0/24"}
|
|
330
|
+
assert "www.evilcorp.org" in preset_whitelist_baked.seeds
|
|
331
|
+
assert "www.evilcorp.com" in preset_whitelist_baked.seeds
|
|
332
|
+
assert "www.evilcorp.org" not in preset_whitelist_baked.target.whitelist
|
|
333
|
+
assert "www.evilcorp.com" not in preset_whitelist_baked.target.whitelist
|
|
316
334
|
assert "1.2.3.4" in preset_whitelist_baked.whitelist
|
|
317
335
|
assert not preset_whitelist_baked.in_scope("www.evilcorp.org")
|
|
318
336
|
assert not preset_whitelist_baked.in_scope("www.evilcorp.com")
|
|
@@ -324,18 +342,18 @@ def test_preset_scope():
|
|
|
324
342
|
preset_nowhitelist2 = Preset("evilcorp.de")
|
|
325
343
|
preset_nowhitelist1_baked = preset_nowhitelist1.bake()
|
|
326
344
|
preset_nowhitelist2_baked = preset_nowhitelist2.bake()
|
|
327
|
-
assert
|
|
328
|
-
assert
|
|
329
|
-
assert
|
|
330
|
-
assert
|
|
345
|
+
assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com"}
|
|
346
|
+
assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.de"}
|
|
347
|
+
assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com"}
|
|
348
|
+
assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.de"}
|
|
331
349
|
preset_nowhitelist1.merge(preset_nowhitelist2)
|
|
332
350
|
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.
|
|
351
|
+
assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com", "evilcorp.de"}
|
|
352
|
+
assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.de"}
|
|
353
|
+
assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com", "evilcorp.de"}
|
|
354
|
+
assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.de"}
|
|
355
|
+
assert "www.evilcorp.com" in preset_nowhitelist1_baked.seeds
|
|
356
|
+
assert "www.evilcorp.de" in preset_nowhitelist1_baked.seeds
|
|
339
357
|
assert "www.evilcorp.com" in preset_nowhitelist1_baked.target.seeds
|
|
340
358
|
assert "www.evilcorp.de" in preset_nowhitelist1_baked.target.seeds
|
|
341
359
|
assert "www.evilcorp.com" in preset_nowhitelist1_baked.whitelist
|
|
@@ -352,10 +370,10 @@ def test_preset_scope():
|
|
|
352
370
|
preset_nowhitelist2.merge(preset_nowhitelist1)
|
|
353
371
|
preset_nowhitelist1_baked = preset_nowhitelist1.bake()
|
|
354
372
|
preset_nowhitelist2_baked = preset_nowhitelist2.bake()
|
|
355
|
-
assert
|
|
356
|
-
assert
|
|
357
|
-
assert
|
|
358
|
-
assert
|
|
373
|
+
assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com"}
|
|
374
|
+
assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.com", "evilcorp.de"}
|
|
375
|
+
assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com"}
|
|
376
|
+
assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.com", "evilcorp.de"}
|
|
359
377
|
|
|
360
378
|
|
|
361
379
|
@pytest.mark.asyncio
|
|
@@ -369,30 +387,30 @@ async def test_preset_logging():
|
|
|
369
387
|
|
|
370
388
|
try:
|
|
371
389
|
silent_preset = Preset(silent=True)
|
|
372
|
-
assert silent_preset.silent
|
|
373
|
-
assert silent_preset.debug
|
|
374
|
-
assert silent_preset.verbose
|
|
390
|
+
assert silent_preset.silent is True
|
|
391
|
+
assert silent_preset.debug is False
|
|
392
|
+
assert silent_preset.verbose is False
|
|
375
393
|
assert original_log_level == CORE.logger.log_level
|
|
376
394
|
debug_preset = Preset(debug=True)
|
|
377
|
-
assert debug_preset.silent
|
|
378
|
-
assert debug_preset.debug
|
|
379
|
-
assert debug_preset.verbose
|
|
395
|
+
assert debug_preset.silent is False
|
|
396
|
+
assert debug_preset.debug is True
|
|
397
|
+
assert debug_preset.verbose is False
|
|
380
398
|
assert original_log_level == CORE.logger.log_level
|
|
381
399
|
verbose_preset = Preset(verbose=True)
|
|
382
|
-
assert verbose_preset.silent
|
|
383
|
-
assert verbose_preset.debug
|
|
384
|
-
assert verbose_preset.verbose
|
|
400
|
+
assert verbose_preset.silent is False
|
|
401
|
+
assert verbose_preset.debug is False
|
|
402
|
+
assert verbose_preset.verbose is True
|
|
385
403
|
assert original_log_level == CORE.logger.log_level
|
|
386
404
|
|
|
387
405
|
# test conflicting verbosity levels
|
|
388
406
|
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
|
|
407
|
+
assert silent_and_verbose.silent is True
|
|
408
|
+
assert silent_and_verbose.debug is False
|
|
409
|
+
assert silent_and_verbose.verbose is True
|
|
392
410
|
baked = silent_and_verbose.bake()
|
|
393
|
-
assert baked.silent
|
|
394
|
-
assert baked.debug
|
|
395
|
-
assert baked.verbose
|
|
411
|
+
assert baked.silent is True
|
|
412
|
+
assert baked.debug is False
|
|
413
|
+
assert baked.verbose is False
|
|
396
414
|
assert baked.core.logger.log_level == original_log_level
|
|
397
415
|
baked = silent_and_verbose.bake(scan=scan)
|
|
398
416
|
assert baked.core.logger.log_level == logging.CRITICAL
|
|
@@ -402,13 +420,13 @@ async def test_preset_logging():
|
|
|
402
420
|
assert CORE.logger.log_level == original_log_level
|
|
403
421
|
|
|
404
422
|
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
|
|
423
|
+
assert silent_and_debug.silent is True
|
|
424
|
+
assert silent_and_debug.debug is True
|
|
425
|
+
assert silent_and_debug.verbose is False
|
|
408
426
|
baked = silent_and_debug.bake()
|
|
409
|
-
assert baked.silent
|
|
410
|
-
assert baked.debug
|
|
411
|
-
assert baked.verbose
|
|
427
|
+
assert baked.silent is True
|
|
428
|
+
assert baked.debug is False
|
|
429
|
+
assert baked.verbose is False
|
|
412
430
|
assert baked.core.logger.log_level == original_log_level
|
|
413
431
|
baked = silent_and_debug.bake(scan=scan)
|
|
414
432
|
assert baked.core.logger.log_level == logging.CRITICAL
|
|
@@ -418,13 +436,13 @@ async def test_preset_logging():
|
|
|
418
436
|
assert CORE.logger.log_level == original_log_level
|
|
419
437
|
|
|
420
438
|
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
|
|
439
|
+
assert debug_and_verbose.silent is False
|
|
440
|
+
assert debug_and_verbose.debug is True
|
|
441
|
+
assert debug_and_verbose.verbose is True
|
|
424
442
|
baked = debug_and_verbose.bake()
|
|
425
|
-
assert baked.silent
|
|
426
|
-
assert baked.debug
|
|
427
|
-
assert baked.verbose
|
|
443
|
+
assert baked.silent is False
|
|
444
|
+
assert baked.debug is True
|
|
445
|
+
assert baked.verbose is False
|
|
428
446
|
assert baked.core.logger.log_level == original_log_level
|
|
429
447
|
baked = debug_and_verbose.bake(scan=scan)
|
|
430
448
|
assert baked.core.logger.log_level == logging.DEBUG
|
|
@@ -434,13 +452,13 @@ async def test_preset_logging():
|
|
|
434
452
|
assert CORE.logger.log_level == original_log_level
|
|
435
453
|
|
|
436
454
|
all_preset = Preset(verbose=True, debug=True, silent=True)
|
|
437
|
-
assert all_preset.silent
|
|
438
|
-
assert all_preset.debug
|
|
439
|
-
assert all_preset.verbose
|
|
455
|
+
assert all_preset.silent is True
|
|
456
|
+
assert all_preset.debug is True
|
|
457
|
+
assert all_preset.verbose is True
|
|
440
458
|
baked = all_preset.bake()
|
|
441
|
-
assert baked.silent
|
|
442
|
-
assert baked.debug
|
|
443
|
-
assert baked.verbose
|
|
459
|
+
assert baked.silent is True
|
|
460
|
+
assert baked.debug is False
|
|
461
|
+
assert baked.verbose is False
|
|
444
462
|
assert baked.core.logger.log_level == original_log_level
|
|
445
463
|
baked = all_preset.bake(scan=scan)
|
|
446
464
|
assert baked.core.logger.log_level == logging.CRITICAL
|
|
@@ -527,12 +545,26 @@ def test_preset_module_resolution(clean_default_config):
|
|
|
527
545
|
assert set(preset.scan_modules) == {"wayback"}
|
|
528
546
|
|
|
529
547
|
# modules + module exclusions
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
assert
|
|
548
|
+
preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "wappalyzer", "wayback"]).bake()
|
|
549
|
+
baked_preset = preset.bake()
|
|
550
|
+
assert baked_preset.modules == {
|
|
551
|
+
"wayback",
|
|
552
|
+
"cloudcheck",
|
|
553
|
+
"python",
|
|
554
|
+
"json",
|
|
555
|
+
"speculate",
|
|
556
|
+
"dnsresolve",
|
|
557
|
+
"aggregate",
|
|
558
|
+
"excavate",
|
|
559
|
+
"txt",
|
|
560
|
+
"httpx",
|
|
561
|
+
"csv",
|
|
562
|
+
"wappalyzer",
|
|
563
|
+
}
|
|
533
564
|
|
|
534
565
|
|
|
535
|
-
|
|
566
|
+
@pytest.mark.asyncio
|
|
567
|
+
async def test_preset_module_loader():
|
|
536
568
|
custom_module_dir = bbot_test_dir / "custom_module_dir"
|
|
537
569
|
custom_module_dir_2 = custom_module_dir / "asdf"
|
|
538
570
|
custom_output_module_dir = custom_module_dir / "output"
|
|
@@ -640,6 +672,43 @@ class TestModule4(BaseModule):
|
|
|
640
672
|
# reset module_loader
|
|
641
673
|
preset2.module_loader.__init__()
|
|
642
674
|
|
|
675
|
+
# custom module dir via preset
|
|
676
|
+
custom_module_dir_3 = bbot_test_dir / "custom_module_dir_3"
|
|
677
|
+
custom_module_dir_3.mkdir(exist_ok=True, parents=True)
|
|
678
|
+
custom_module_5 = custom_module_dir_3 / "testmodule5.py"
|
|
679
|
+
with open(custom_module_5, "w") as f:
|
|
680
|
+
f.write(
|
|
681
|
+
"""
|
|
682
|
+
from bbot.modules.base import BaseModule
|
|
683
|
+
|
|
684
|
+
class TestModule5(BaseModule):
|
|
685
|
+
watched_events = ["TECHNOLOGY"]
|
|
686
|
+
produced_events = ["FINDING"]
|
|
687
|
+
"""
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
preset = Preset.from_yaml_string(
|
|
691
|
+
"""
|
|
692
|
+
modules:
|
|
693
|
+
- testmodule5
|
|
694
|
+
"""
|
|
695
|
+
)
|
|
696
|
+
# should fail
|
|
697
|
+
with pytest.raises(ValidationError):
|
|
698
|
+
scan = Scanner(preset=preset)
|
|
699
|
+
|
|
700
|
+
preset = Preset.from_yaml_string(
|
|
701
|
+
f"""
|
|
702
|
+
module_dirs:
|
|
703
|
+
- {custom_module_dir_3}
|
|
704
|
+
modules:
|
|
705
|
+
- testmodule5
|
|
706
|
+
"""
|
|
707
|
+
)
|
|
708
|
+
scan = Scanner(preset=preset)
|
|
709
|
+
await scan._prep()
|
|
710
|
+
assert "testmodule5" in scan.modules
|
|
711
|
+
|
|
643
712
|
|
|
644
713
|
def test_preset_include():
|
|
645
714
|
|
|
@@ -827,9 +896,9 @@ def test_preset_require_exclude():
|
|
|
827
896
|
dnsbrute_flags = preset.preloaded_module("dnsbrute").get("flags", [])
|
|
828
897
|
assert "subdomain-enum" in dnsbrute_flags
|
|
829
898
|
assert "active" in dnsbrute_flags
|
|
830
|
-
assert
|
|
899
|
+
assert "passive" not in dnsbrute_flags
|
|
831
900
|
assert "aggressive" in dnsbrute_flags
|
|
832
|
-
assert
|
|
901
|
+
assert "safe" not in dnsbrute_flags
|
|
833
902
|
assert "dnsbrute" in [x[0] for x in module_flags]
|
|
834
903
|
assert "certspotter" in [x[0] for x in module_flags]
|
|
835
904
|
assert "c99" in [x[0] for x in module_flags]
|
|
@@ -843,7 +912,7 @@ def test_preset_require_exclude():
|
|
|
843
912
|
assert len(preset.modules) > 25
|
|
844
913
|
module_flags = list(get_module_flags(preset))
|
|
845
914
|
assert "chaos" in [x[0] for x in module_flags]
|
|
846
|
-
assert
|
|
915
|
+
assert "httpx" not in [x[0] for x in module_flags]
|
|
847
916
|
assert all("passive" in flags for module, flags in module_flags)
|
|
848
917
|
assert not any("active" in flags for module, flags in module_flags)
|
|
849
918
|
assert any("safe" in flags for module, flags in module_flags)
|
|
@@ -854,7 +923,7 @@ def test_preset_require_exclude():
|
|
|
854
923
|
assert len(preset.modules) > 25
|
|
855
924
|
module_flags = list(get_module_flags(preset))
|
|
856
925
|
assert "chaos" in [x[0] for x in module_flags]
|
|
857
|
-
assert
|
|
926
|
+
assert "httpx" not in [x[0] for x in module_flags]
|
|
858
927
|
assert all("passive" in flags for module, flags in module_flags)
|
|
859
928
|
assert not any("active" in flags for module, flags in module_flags)
|
|
860
929
|
assert any("safe" in flags for module, flags in module_flags)
|
|
@@ -864,7 +933,7 @@ def test_preset_require_exclude():
|
|
|
864
933
|
preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute"]).bake()
|
|
865
934
|
assert len(preset.modules) > 25
|
|
866
935
|
module_flags = list(get_module_flags(preset))
|
|
867
|
-
assert
|
|
936
|
+
assert "dnsbrute" not in [x[0] for x in module_flags]
|
|
868
937
|
assert "httpx" in [x[0] for x in module_flags]
|
|
869
938
|
assert any("passive" in flags for module, flags in module_flags)
|
|
870
939
|
assert any("active" in flags for module, flags in module_flags)
|
|
@@ -875,7 +944,7 @@ def test_preset_require_exclude():
|
|
|
875
944
|
preset = Preset(flags=["subdomain-enum"], require_flags=["safe", "passive"]).bake()
|
|
876
945
|
assert len(preset.modules) > 25
|
|
877
946
|
module_flags = list(get_module_flags(preset))
|
|
878
|
-
assert
|
|
947
|
+
assert "dnsbrute" not in [x[0] for x in module_flags]
|
|
879
948
|
assert all("passive" in flags and "safe" in flags for module, flags in module_flags)
|
|
880
949
|
assert all("active" not in flags and "aggressive" not in flags for module, flags in module_flags)
|
|
881
950
|
assert not any("active" in flags for module, flags in module_flags)
|
|
@@ -885,7 +954,7 @@ def test_preset_require_exclude():
|
|
|
885
954
|
preset = Preset(flags=["subdomain-enum"], exclude_flags=["aggressive", "active"]).bake()
|
|
886
955
|
assert len(preset.modules) > 25
|
|
887
956
|
module_flags = list(get_module_flags(preset))
|
|
888
|
-
assert
|
|
957
|
+
assert "dnsbrute" not in [x[0] for x in module_flags]
|
|
889
958
|
assert all("passive" in flags and "safe" in flags for module, flags in module_flags)
|
|
890
959
|
assert all("active" not in flags and "aggressive" not in flags for module, flags in module_flags)
|
|
891
960
|
assert not any("active" in flags for module, flags in module_flags)
|
|
@@ -895,10 +964,29 @@ def test_preset_require_exclude():
|
|
|
895
964
|
preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute", "c99"]).bake()
|
|
896
965
|
assert len(preset.modules) > 25
|
|
897
966
|
module_flags = list(get_module_flags(preset))
|
|
898
|
-
assert
|
|
967
|
+
assert "dnsbrute" not in [x[0] for x in module_flags]
|
|
899
968
|
assert "certspotter" in [x[0] for x in module_flags]
|
|
900
|
-
assert
|
|
969
|
+
assert "c99" not in [x[0] for x in module_flags]
|
|
901
970
|
assert any("passive" in flags for module, flags in module_flags)
|
|
902
971
|
assert any("active" in flags for module, flags in module_flags)
|
|
903
972
|
assert any("safe" in flags for module, flags in module_flags)
|
|
904
973
|
assert any("aggressive" in flags for module, flags in module_flags)
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
@pytest.mark.asyncio
|
|
977
|
+
async def test_preset_output_dir():
|
|
978
|
+
output_dir = bbot_test_dir / "preset_output_dir"
|
|
979
|
+
preset = Preset.from_yaml_string(
|
|
980
|
+
f"""
|
|
981
|
+
output_dir: {output_dir}
|
|
982
|
+
scan_name: bbot_test
|
|
983
|
+
"""
|
|
984
|
+
)
|
|
985
|
+
scan = Scanner(preset=preset)
|
|
986
|
+
await scan.async_start_without_generator()
|
|
987
|
+
scan_dir = output_dir / "bbot_test"
|
|
988
|
+
assert scan_dir.is_dir()
|
|
989
|
+
output_file = scan_dir / "output.txt"
|
|
990
|
+
assert output_file.is_file()
|
|
991
|
+
|
|
992
|
+
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()
|