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
|
@@ -29,7 +29,7 @@ async def test_web_engine(bbot_scanner, bbot_httpserver, httpx_mock):
|
|
|
29
29
|
urls = [f"{base_url}{i}" for i in range(num_urls)]
|
|
30
30
|
responses = [r async for r in scan.helpers.request_batch(urls)]
|
|
31
31
|
assert len(responses) == 100
|
|
32
|
-
assert all(
|
|
32
|
+
assert all(r[1].status_code == 200 and r[1].text.startswith(f"{r[0]}: ") for r in responses)
|
|
33
33
|
|
|
34
34
|
# request_batch w/ cancellation
|
|
35
35
|
agen = scan.helpers.request_batch(urls)
|
|
@@ -153,9 +153,12 @@ async def test_web_helpers(bbot_scanner, bbot_httpserver, httpx_mock):
|
|
|
153
153
|
|
|
154
154
|
await scan._cleanup()
|
|
155
155
|
|
|
156
|
-
scan1 = bbot_scanner("8.8.8.8")
|
|
156
|
+
scan1 = bbot_scanner("8.8.8.8", modules=["ipneighbor"])
|
|
157
157
|
scan2 = bbot_scanner("127.0.0.1")
|
|
158
158
|
|
|
159
|
+
await scan1._prep()
|
|
160
|
+
module = scan1.modules["ipneighbor"]
|
|
161
|
+
|
|
159
162
|
web_config = CORE.config.get("web", {})
|
|
160
163
|
user_agent = web_config.get("user_agent", "")
|
|
161
164
|
headers = {"User-Agent": user_agent}
|
|
@@ -208,14 +211,14 @@ async def test_web_helpers(bbot_scanner, bbot_httpserver, httpx_mock):
|
|
|
208
211
|
url = bbot_httpserver.url_for(path)
|
|
209
212
|
bbot_httpserver.expect_request(uri=path).respond_with_data(download_content, status=200)
|
|
210
213
|
webpage = await scan1.helpers.request(url)
|
|
211
|
-
assert webpage,
|
|
214
|
+
assert webpage, "Webpage is False"
|
|
212
215
|
soup = scan1.helpers.beautifulsoup(webpage, "html.parser")
|
|
213
|
-
assert soup,
|
|
216
|
+
assert soup, "Soup is False"
|
|
214
217
|
# pretty_print = soup.prettify()
|
|
215
218
|
# assert pretty_print, f"PrettyPrint is False"
|
|
216
219
|
# scan1.helpers.log.info(f"{pretty_print}")
|
|
217
220
|
html_text = soup.find(text="Example Domain")
|
|
218
|
-
assert html_text,
|
|
221
|
+
assert html_text, "Find HTML Text is False"
|
|
219
222
|
|
|
220
223
|
# 404
|
|
221
224
|
path = "/test_http_helpers_download_404"
|
|
@@ -252,7 +255,7 @@ async def test_web_helpers(bbot_scanner, bbot_httpserver, httpx_mock):
|
|
|
252
255
|
uri=f"{base_path}/3", query_string={"page_size": "100", "offset": "200"}
|
|
253
256
|
).respond_with_data("page3")
|
|
254
257
|
results = []
|
|
255
|
-
agen =
|
|
258
|
+
agen = module.api_page_iter(template_url)
|
|
256
259
|
try:
|
|
257
260
|
async for result in agen:
|
|
258
261
|
if result and result.text.startswith("page"):
|
|
@@ -262,7 +265,7 @@ async def test_web_helpers(bbot_scanner, bbot_httpserver, httpx_mock):
|
|
|
262
265
|
finally:
|
|
263
266
|
await agen.aclose()
|
|
264
267
|
assert not results
|
|
265
|
-
agen =
|
|
268
|
+
agen = module.api_page_iter(template_url, json=False)
|
|
266
269
|
try:
|
|
267
270
|
async for result in agen:
|
|
268
271
|
if result and result.text.startswith("page"):
|
|
@@ -386,7 +389,7 @@ async def test_web_http_compare(httpx_mock, bbot_scanner):
|
|
|
386
389
|
await compare_helper.compare("http://www.example.com", check_reflection=True)
|
|
387
390
|
compare_helper.compare_body({"asdf": "fdsa"}, {"fdsa": "asdf"})
|
|
388
391
|
for mode in ("getparam", "header", "cookie"):
|
|
389
|
-
assert await compare_helper.canary_check("http://www.example.com", mode=mode)
|
|
392
|
+
assert await compare_helper.canary_check("http://www.example.com", mode=mode) is True
|
|
390
393
|
|
|
391
394
|
await scan._cleanup()
|
|
392
395
|
|
|
@@ -468,6 +471,9 @@ async def test_web_cookies(bbot_scanner, httpx_mock):
|
|
|
468
471
|
# but that they're not sent in the response
|
|
469
472
|
with pytest.raises(httpx.TimeoutException):
|
|
470
473
|
r = await client2.get(url="http://www2.evilcorp.com/cookies/test")
|
|
474
|
+
# make sure cookies are sent
|
|
475
|
+
r = await client2.get(url="http://www2.evilcorp.com/cookies/test", cookies={"wats": "fdsa"})
|
|
476
|
+
assert r.status_code == 200
|
|
471
477
|
# make sure we can manually send cookies
|
|
472
478
|
httpx_mock.add_response(url="http://www2.evilcorp.com/cookies/test2", match_headers={"Cookie": "fdsa=wats"})
|
|
473
479
|
r = await client2.get(url="http://www2.evilcorp.com/cookies/test2", cookies={"fdsa": "wats"})
|
|
@@ -20,6 +20,8 @@ class ModuleTestBase:
|
|
|
20
20
|
config_overrides = {}
|
|
21
21
|
modules_overrides = None
|
|
22
22
|
log = logging.getLogger("bbot")
|
|
23
|
+
# if True, the test will be skipped (useful for tests that require docker)
|
|
24
|
+
skip_distro_tests = False
|
|
23
25
|
|
|
24
26
|
class ModuleTest:
|
|
25
27
|
def __init__(
|
|
@@ -89,33 +91,39 @@ class ModuleTestBase:
|
|
|
89
91
|
async def module_test(
|
|
90
92
|
self, httpx_mock, bbot_httpserver, bbot_httpserver_ssl, monkeypatch, request, caplog, capsys
|
|
91
93
|
):
|
|
94
|
+
# Skip dastardly test if we're in the distro tests (because dastardly uses docker)
|
|
95
|
+
if os.getenv("BBOT_DISTRO_TESTS") and self.skip_distro_tests:
|
|
96
|
+
pytest.skip("Skipping module_test for dastardly module due to BBOT_DISTRO_TESTS environment variable")
|
|
97
|
+
|
|
92
98
|
self.log.info(f"Starting {self.name} module test")
|
|
93
99
|
module_test = self.ModuleTest(
|
|
94
100
|
self, httpx_mock, bbot_httpserver, bbot_httpserver_ssl, monkeypatch, request, caplog, capsys
|
|
95
101
|
)
|
|
96
|
-
self.log.debug(
|
|
102
|
+
self.log.debug("Mocking DNS")
|
|
97
103
|
await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.88"]}})
|
|
98
|
-
self.log.debug(
|
|
104
|
+
self.log.debug("Executing setup_before_prep()")
|
|
99
105
|
await self.setup_before_prep(module_test)
|
|
100
|
-
self.log.debug(
|
|
106
|
+
self.log.debug("Executing scan._prep()")
|
|
101
107
|
await module_test.scan._prep()
|
|
102
|
-
self.log.debug(
|
|
108
|
+
self.log.debug("Executing setup_after_prep()")
|
|
103
109
|
await self.setup_after_prep(module_test)
|
|
104
|
-
self.log.debug(
|
|
110
|
+
self.log.debug("Starting scan")
|
|
105
111
|
module_test.events = [e async for e in module_test.scan.async_start()]
|
|
106
112
|
self.log.debug(f"Finished {module_test.name} module test")
|
|
107
113
|
yield module_test
|
|
108
114
|
|
|
109
115
|
@pytest.mark.asyncio
|
|
110
116
|
async def test_module_run(self, module_test):
|
|
111
|
-
|
|
117
|
+
from bbot.core.helpers.misc import execute_sync_or_async
|
|
118
|
+
|
|
119
|
+
await execute_sync_or_async(self.check, module_test, module_test.events)
|
|
112
120
|
module_test.log.info(f"Finished {self.name} module test")
|
|
113
121
|
current_task = asyncio.current_task()
|
|
114
122
|
tasks = [t for t in asyncio.all_tasks() if t != current_task]
|
|
115
123
|
if len(tasks):
|
|
116
124
|
module_test.log.info(f"Unfinished tasks detected: {tasks}")
|
|
117
125
|
else:
|
|
118
|
-
module_test.log.info(
|
|
126
|
+
module_test.log.info("No unfinished tasks detected")
|
|
119
127
|
|
|
120
128
|
def check(self, module_test, events):
|
|
121
129
|
assert False, f"Must override {self.name}.check()"
|
|
@@ -5,7 +5,7 @@ class TestAnubisdb(ModuleTestBase):
|
|
|
5
5
|
async def setup_after_prep(self, module_test):
|
|
6
6
|
module_test.module.abort_if = lambda e: False
|
|
7
7
|
module_test.httpx_mock.add_response(
|
|
8
|
-
url=
|
|
8
|
+
url="https://jldc.me/anubis/subdomains/blacklanternsecurity.com",
|
|
9
9
|
json=["asdf.blacklanternsecurity.com", "zzzz.blacklanternsecurity.com"],
|
|
10
10
|
)
|
|
11
11
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from .base import ModuleTestBase, tempapkfile
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TestAPKPure(ModuleTestBase):
|
|
6
|
+
modules_overrides = ["apkpure", "google_playstore", "speculate"]
|
|
7
|
+
apk_file = tempapkfile()
|
|
8
|
+
|
|
9
|
+
async def setup_after_prep(self, module_test):
|
|
10
|
+
await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.99"]}})
|
|
11
|
+
module_test.httpx_mock.add_response(
|
|
12
|
+
url="https://play.google.com/store/search?q=blacklanternsecurity&c=apps",
|
|
13
|
+
text="""<!DOCTYPE html>
|
|
14
|
+
<html>
|
|
15
|
+
<head>
|
|
16
|
+
<title>"blacklanternsecurity" - Android Apps on Google Play</title>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<a href="/store/apps/details?id=com.bbot.test&pcampaignid=dontmatchme&pli=1"/>
|
|
20
|
+
</body>
|
|
21
|
+
</html>""",
|
|
22
|
+
)
|
|
23
|
+
module_test.httpx_mock.add_response(
|
|
24
|
+
url="https://play.google.com/store/apps/details?id=com.bbot.test",
|
|
25
|
+
text="""<!DOCTYPE html>
|
|
26
|
+
<html>
|
|
27
|
+
<head>
|
|
28
|
+
<title>BBOT</title>
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
<meta name="appstore:developer_url" content="https://www.blacklanternsecurity.com">
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</body>
|
|
35
|
+
</html>""",
|
|
36
|
+
)
|
|
37
|
+
module_test.httpx_mock.add_response(
|
|
38
|
+
url="https://d.apkpure.com/b/XAPK/com.bbot.test?version=latest",
|
|
39
|
+
content=self.apk_file,
|
|
40
|
+
headers={
|
|
41
|
+
"Content-Type": "application/vnd.android.package-archive",
|
|
42
|
+
"Content-Disposition": "attachment; filename=com.bbot.test.apk",
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def check(self, module_test, events):
|
|
47
|
+
assert len(events) == 6
|
|
48
|
+
assert 1 == len(
|
|
49
|
+
[
|
|
50
|
+
e
|
|
51
|
+
for e in events
|
|
52
|
+
if e.type == "DNS_NAME" and e.data == "blacklanternsecurity.com" and e.scope_distance == 0
|
|
53
|
+
]
|
|
54
|
+
), "Failed to emit target DNS_NAME"
|
|
55
|
+
assert 1 == len(
|
|
56
|
+
[e for e in events if e.type == "ORG_STUB" and e.data == "blacklanternsecurity" and e.scope_distance == 0]
|
|
57
|
+
), "Failed to find ORG_STUB"
|
|
58
|
+
assert 1 == len(
|
|
59
|
+
[
|
|
60
|
+
e
|
|
61
|
+
for e in events
|
|
62
|
+
if e.type == "MOBILE_APP"
|
|
63
|
+
and "android" in e.tags
|
|
64
|
+
and e.data["id"] == "com.bbot.test"
|
|
65
|
+
and e.data["url"] == "https://play.google.com/store/apps/details?id=com.bbot.test"
|
|
66
|
+
]
|
|
67
|
+
), "Failed to find bbot android app"
|
|
68
|
+
filesystem_event = [e for e in events if e.type == "FILESYSTEM" and "com.bbot.test.apk" in e.data["path"]]
|
|
69
|
+
assert 1 == len(filesystem_event), "Failed to download apk"
|
|
70
|
+
file = Path(filesystem_event[0].data["path"])
|
|
71
|
+
assert file.is_file(), "Destination apk doesn't exist"
|
|
@@ -10,7 +10,6 @@ class TestAsset_Inventory(ModuleTestBase):
|
|
|
10
10
|
masscan_output = """{ "ip": "127.0.0.1", "timestamp": "1680197558", "ports": [ {"port": 9999, "proto": "tcp", "status": "open", "reason": "syn-ack", "ttl": 54} ] }"""
|
|
11
11
|
|
|
12
12
|
async def setup_before_prep(self, module_test):
|
|
13
|
-
|
|
14
13
|
async def run_masscan(command, *args, **kwargs):
|
|
15
14
|
if "masscan" in command[:2]:
|
|
16
15
|
targets = open(command[11]).read().splitlines()
|
|
@@ -22,7 +22,7 @@ class TestAzure_Realm(ModuleTestBase):
|
|
|
22
22
|
async def setup_after_prep(self, module_test):
|
|
23
23
|
await module_test.mock_dns({"evilcorp.com": {"A": ["127.0.0.5"]}})
|
|
24
24
|
module_test.httpx_mock.add_response(
|
|
25
|
-
url=
|
|
25
|
+
url="https://login.microsoftonline.com/getuserrealm.srf?login=test@evilcorp.com",
|
|
26
26
|
json=self.response_json,
|
|
27
27
|
)
|
|
28
28
|
|
|
@@ -31,9 +31,9 @@ class TestBaddns_cname_nxdomain(BaseTestBaddns):
|
|
|
31
31
|
module_test.monkeypatch.setattr(WhoisManager, "dispatchWHOIS", self.dispatchWHOIS)
|
|
32
32
|
|
|
33
33
|
def check(self, module_test, events):
|
|
34
|
-
assert any(
|
|
35
|
-
assert any(
|
|
36
|
-
assert any(
|
|
34
|
+
assert any(e.data == "baddns.azurewebsites.net" for e in events), "CNAME detection failed"
|
|
35
|
+
assert any(e.type == "VULNERABILITY" for e in events), "Failed to emit VULNERABILITY"
|
|
36
|
+
assert any("baddns-cname" in e.tags for e in events), "Failed to add baddns tag"
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class TestBaddns_cname_signature(BaseTestBaddns):
|
|
@@ -60,8 +60,8 @@ class TestBaddns_cname_signature(BaseTestBaddns):
|
|
|
60
60
|
module_test.monkeypatch.setattr(WhoisManager, "dispatchWHOIS", self.dispatchWHOIS)
|
|
61
61
|
|
|
62
62
|
def check(self, module_test, events):
|
|
63
|
-
assert any(
|
|
63
|
+
assert any(e for e in events)
|
|
64
64
|
assert any(
|
|
65
|
-
|
|
65
|
+
e.type == "VULNERABILITY" and "bigcartel.com" in e.data["description"] for e in events
|
|
66
66
|
), "Failed to emit VULNERABILITY"
|
|
67
|
-
assert any(
|
|
67
|
+
assert any("baddns-cname" in e.tags for e in events), "Failed to add baddns tag"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from .base import ModuleTestBase
|
|
2
|
+
from bbot.modules.base import BaseModule
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BaseTestBaddns(ModuleTestBase):
|
|
6
|
+
modules_overrides = ["baddns_direct"]
|
|
7
|
+
targets = ["bad.dns"]
|
|
8
|
+
config_overrides = {"dns": {"minimal": False}, "cloudcheck": True}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestBaddns_direct_cloudflare(BaseTestBaddns):
|
|
12
|
+
targets = ["bad.dns:8888"]
|
|
13
|
+
modules_overrides = ["baddns_direct"]
|
|
14
|
+
|
|
15
|
+
async def dispatchWHOIS(self):
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
class DummyModule(BaseModule):
|
|
19
|
+
watched_events = ["DNS_NAME"]
|
|
20
|
+
_name = "dummy_module"
|
|
21
|
+
events_seen = []
|
|
22
|
+
|
|
23
|
+
async def handle_event(self, event):
|
|
24
|
+
if event.data == "bad.dns":
|
|
25
|
+
await self.helpers.sleep(0.5)
|
|
26
|
+
self.events_seen.append(event.data)
|
|
27
|
+
url = "http://bad.dns:8888/"
|
|
28
|
+
url_event = self.scan.make_event(
|
|
29
|
+
url, "URL", parent=self.scan.root_event, tags=["cdn-cloudflare", "in-scope", "status-401"]
|
|
30
|
+
)
|
|
31
|
+
if url_event is not None:
|
|
32
|
+
await self.emit_event(url_event)
|
|
33
|
+
|
|
34
|
+
async def setup_after_prep(self, module_test):
|
|
35
|
+
from baddns.base import BadDNS_base
|
|
36
|
+
from baddns.lib.whoismanager import WhoisManager
|
|
37
|
+
|
|
38
|
+
def set_target(self, target):
|
|
39
|
+
return "127.0.0.1:8888"
|
|
40
|
+
|
|
41
|
+
self.module_test = module_test
|
|
42
|
+
|
|
43
|
+
self.dummy_module = self.DummyModule(module_test.scan)
|
|
44
|
+
module_test.scan.modules["dummy_module"] = self.dummy_module
|
|
45
|
+
|
|
46
|
+
expect_args = {"method": "GET", "uri": "/"}
|
|
47
|
+
respond_args = {"response_data": "The specified bucket does not exist", "status": 401}
|
|
48
|
+
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
49
|
+
|
|
50
|
+
await module_test.mock_dns({"bad.dns": {"A": ["127.0.0.1"]}})
|
|
51
|
+
|
|
52
|
+
module_test.monkeypatch.setattr(BadDNS_base, "set_target", set_target)
|
|
53
|
+
module_test.monkeypatch.setattr(WhoisManager, "dispatchWHOIS", self.dispatchWHOIS)
|
|
54
|
+
|
|
55
|
+
def check(self, module_test, events):
|
|
56
|
+
assert any(
|
|
57
|
+
e.type == "FINDING"
|
|
58
|
+
and "Possible [AWS Bucket Takeover Detection] via direct BadDNS analysis. Indicator: [[Words: The specified bucket does not exist | Condition: and | Part: body] Matchers-Condition: and] Trigger: [self] baddns Module: [CNAME]"
|
|
59
|
+
in e.data["description"]
|
|
60
|
+
for e in events
|
|
61
|
+
), "Failed to emit FINDING"
|
|
62
|
+
assert any("baddns-cname" in e.tags for e in events), "Failed to add baddns tag"
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import random
|
|
2
|
+
|
|
1
3
|
from .base import ModuleTestBase
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
class TestBeVigil(ModuleTestBase):
|
|
7
|
+
module_name = "bevigil"
|
|
5
8
|
config_overrides = {"modules": {"bevigil": {"api_key": "asdf", "urls": True}}}
|
|
6
9
|
|
|
7
10
|
async def setup_after_prep(self, module_test):
|
|
8
11
|
module_test.httpx_mock.add_response(
|
|
9
|
-
url=
|
|
12
|
+
url="https://osint.bevigil.com/api/blacklanternsecurity.com/subdomains/",
|
|
13
|
+
match_headers={"X-Access-Token": "asdf"},
|
|
10
14
|
json={
|
|
11
15
|
"domain": "blacklanternsecurity.com",
|
|
12
16
|
"subdomains": [
|
|
@@ -15,10 +19,33 @@ class TestBeVigil(ModuleTestBase):
|
|
|
15
19
|
},
|
|
16
20
|
)
|
|
17
21
|
module_test.httpx_mock.add_response(
|
|
18
|
-
url=
|
|
22
|
+
url="https://osint.bevigil.com/api/blacklanternsecurity.com/urls/",
|
|
19
23
|
json={"domain": "blacklanternsecurity.com", "urls": ["https://asdf.blacklanternsecurity.com"]},
|
|
20
24
|
)
|
|
21
25
|
|
|
22
26
|
def check(self, module_test, events):
|
|
23
27
|
assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain"
|
|
24
28
|
assert any(e.data == "https://asdf.blacklanternsecurity.com/" for e in events), "Failed to detect url"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TestBeVigilMultiKey(TestBeVigil):
|
|
32
|
+
api_keys = ["1234", "4321", "asdf", "fdsa"]
|
|
33
|
+
random.shuffle(api_keys)
|
|
34
|
+
config_overrides = {"modules": {"bevigil": {"api_key": api_keys, "urls": True}}}
|
|
35
|
+
|
|
36
|
+
async def setup_after_prep(self, module_test):
|
|
37
|
+
module_test.httpx_mock.add_response(
|
|
38
|
+
url="https://osint.bevigil.com/api/blacklanternsecurity.com/subdomains/",
|
|
39
|
+
match_headers={"X-Access-Token": "fdsa"},
|
|
40
|
+
json={
|
|
41
|
+
"domain": "blacklanternsecurity.com",
|
|
42
|
+
"subdomains": [
|
|
43
|
+
"asdf.blacklanternsecurity.com",
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
)
|
|
47
|
+
module_test.httpx_mock.add_response(
|
|
48
|
+
match_headers={"X-Access-Token": "asdf"},
|
|
49
|
+
url="https://osint.bevigil.com/api/blacklanternsecurity.com/urls/",
|
|
50
|
+
json={"domain": "blacklanternsecurity.com", "urls": ["https://asdf.blacklanternsecurity.com"]},
|
|
51
|
+
)
|
|
@@ -6,7 +6,8 @@ class TestBinaryEdge(ModuleTestBase):
|
|
|
6
6
|
|
|
7
7
|
async def setup_before_prep(self, module_test):
|
|
8
8
|
module_test.httpx_mock.add_response(
|
|
9
|
-
url=
|
|
9
|
+
url="https://api.binaryedge.io/v2/query/domains/subdomain/blacklanternsecurity.com",
|
|
10
|
+
match_headers={"X-Key": "asdf"},
|
|
10
11
|
json={
|
|
11
12
|
"query": "blacklanternsecurity.com",
|
|
12
13
|
"page": 1,
|
|
@@ -18,7 +19,8 @@ class TestBinaryEdge(ModuleTestBase):
|
|
|
18
19
|
},
|
|
19
20
|
)
|
|
20
21
|
module_test.httpx_mock.add_response(
|
|
21
|
-
url=
|
|
22
|
+
url="https://api.binaryedge.io/v2/user/subscription",
|
|
23
|
+
match_headers={"X-Key": "asdf"},
|
|
22
24
|
json={
|
|
23
25
|
"subscription": {"name": "Free"},
|
|
24
26
|
"end_date": "2023-06-17",
|
|
@@ -82,8 +82,8 @@ class Bucket_Amazon_Base(ModuleTestBase):
|
|
|
82
82
|
if e.type == "FINDING" and str(e.module) == self.module_name:
|
|
83
83
|
url = e.data.get("url", "")
|
|
84
84
|
assert self.random_bucket_2 in url
|
|
85
|
-
assert
|
|
86
|
-
assert
|
|
85
|
+
assert self.random_bucket_1 not in url
|
|
86
|
+
assert self.random_bucket_3 not in url
|
|
87
87
|
# make sure bucket mutations were found
|
|
88
88
|
assert any(
|
|
89
89
|
e.type == "STORAGE_BUCKET"
|
|
@@ -21,7 +21,7 @@ class TestBucket_Azure_NoDup(ModuleTestBase):
|
|
|
21
21
|
|
|
22
22
|
async def setup_before_prep(self, module_test):
|
|
23
23
|
module_test.httpx_mock.add_response(
|
|
24
|
-
url=
|
|
24
|
+
url="https://tesla.blob.core.windows.net/tesla?restype=container",
|
|
25
25
|
text="",
|
|
26
26
|
)
|
|
27
27
|
await module_test.mock_dns(
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from .base import ModuleTestBase
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestBufferOverrun(ModuleTestBase):
|
|
5
|
+
config_overrides = {"modules": {"bufferoverrun": {"api_key": "asdf", "commercial": False}}}
|
|
6
|
+
|
|
7
|
+
async def setup_before_prep(self, module_test):
|
|
8
|
+
# Mock response for non-commercial API
|
|
9
|
+
module_test.httpx_mock.add_response(
|
|
10
|
+
url="https://tls.bufferover.run/dns?q=.blacklanternsecurity.com",
|
|
11
|
+
match_headers={"x-api-key": "asdf"},
|
|
12
|
+
json={"Results": ["1.2.3.4,example.com,*,*,sub.blacklanternsecurity.com"]},
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
def check(self, module_test, events):
|
|
16
|
+
assert any(e.data == "sub.blacklanternsecurity.com" for e in events), "Failed to detect subdomain for free API"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestBufferOverrunCommercial(ModuleTestBase):
|
|
20
|
+
modules_overrides = ["bufferoverrun"]
|
|
21
|
+
module_name = "bufferoverrun"
|
|
22
|
+
config_overrides = {"modules": {"bufferoverrun": {"api_key": "asdf", "commercial": True}}}
|
|
23
|
+
|
|
24
|
+
async def setup_before_prep(self, module_test):
|
|
25
|
+
# Mock response for commercial API
|
|
26
|
+
module_test.httpx_mock.add_response(
|
|
27
|
+
url="https://bufferover-run-tls.p.rapidapi.com/ipv4/dns?q=.blacklanternsecurity.com",
|
|
28
|
+
match_headers={"x-rapidapi-host": "bufferover-run-tls.p.rapidapi.com", "x-rapidapi-key": "asdf"},
|
|
29
|
+
json={"Results": ["5.6.7.8,blacklanternsecurity.com,*,*,sub.blacklanternsecurity.com"]},
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def check(self, module_test, events):
|
|
33
|
+
assert any(
|
|
34
|
+
e.data == "sub.blacklanternsecurity.com" for e in events
|
|
35
|
+
), "Failed to detect subdomain for commercial API"
|
|
@@ -6,7 +6,7 @@ class TestBuiltWith(ModuleTestBase):
|
|
|
6
6
|
|
|
7
7
|
async def setup_after_prep(self, module_test):
|
|
8
8
|
module_test.httpx_mock.add_response(
|
|
9
|
-
url=
|
|
9
|
+
url="https://api.builtwith.com/v20/api.json?KEY=asdf&LOOKUP=blacklanternsecurity.com&NOMETA=yes&NOATTR=yes&HIDETEXT=yes&HIDEDL=yes",
|
|
10
10
|
json={
|
|
11
11
|
"Results": [
|
|
12
12
|
{
|
|
@@ -91,7 +91,7 @@ class TestBuiltWith(ModuleTestBase):
|
|
|
91
91
|
},
|
|
92
92
|
)
|
|
93
93
|
module_test.httpx_mock.add_response(
|
|
94
|
-
url=
|
|
94
|
+
url="https://api.builtwith.com/redirect1/api.json?KEY=asdf&LOOKUP=blacklanternsecurity.com",
|
|
95
95
|
json={
|
|
96
96
|
"Lookup": "blacklanternsecurity.com",
|
|
97
97
|
"Inbound": [
|
|
@@ -26,7 +26,7 @@ class TestBypass403_collapsethreshold(ModuleTestBase):
|
|
|
26
26
|
async def setup_after_prep(self, module_test):
|
|
27
27
|
respond_args = {"response_data": "alive"}
|
|
28
28
|
|
|
29
|
-
# some of these
|
|
29
|
+
# some of these won't work outside of the module because of the complex logic. This doesn't matter, we just need to get more alerts than the threshold.
|
|
30
30
|
|
|
31
31
|
query_payloads = [
|
|
32
32
|
"%09",
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
|
|
1
3
|
from .base import ModuleTestBase
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
class TestC99(ModuleTestBase):
|
|
7
|
+
module_name = "c99"
|
|
5
8
|
config_overrides = {"modules": {"c99": {"api_key": "asdf"}}}
|
|
6
9
|
|
|
7
10
|
async def setup_before_prep(self, module_test):
|
|
@@ -23,3 +26,126 @@ class TestC99(ModuleTestBase):
|
|
|
23
26
|
|
|
24
27
|
def check(self, module_test, events):
|
|
25
28
|
assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TestC99AbortThreshold1(TestC99):
|
|
32
|
+
config_overrides = {"modules": {"c99": {"api_key": ["6789", "fdsa", "1234", "4321"]}}}
|
|
33
|
+
|
|
34
|
+
async def setup_before_prep(self, module_test):
|
|
35
|
+
module_test.httpx_mock.add_response(
|
|
36
|
+
url="https://api.c99.nl/randomnumber?key=fdsa&between=1,100&json",
|
|
37
|
+
json={"success": True, "output": 65},
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
self.url_count = {}
|
|
41
|
+
|
|
42
|
+
async def custom_callback(request):
|
|
43
|
+
url = str(request.url)
|
|
44
|
+
try:
|
|
45
|
+
self.url_count[url] += 1
|
|
46
|
+
except KeyError:
|
|
47
|
+
self.url_count[url] = 1
|
|
48
|
+
raise httpx.TimeoutException("timeout")
|
|
49
|
+
|
|
50
|
+
module_test.httpx_mock.add_callback(custom_callback)
|
|
51
|
+
|
|
52
|
+
def check(self, module_test, events):
|
|
53
|
+
assert module_test.module.api_failure_abort_threshold == 13
|
|
54
|
+
assert module_test.module.errored is False
|
|
55
|
+
# assert module_test.module._api_request_failures == 4
|
|
56
|
+
assert module_test.module.api_retries == 4
|
|
57
|
+
assert {e.data for e in events if e.type == "DNS_NAME"} == {"blacklanternsecurity.com"}
|
|
58
|
+
assert self.url_count == {
|
|
59
|
+
"https://api.c99.nl/randomnumber?key=6789&between=1,100&json": 1,
|
|
60
|
+
"https://api.c99.nl/randomnumber?key=4321&between=1,100&json": 1,
|
|
61
|
+
"https://api.c99.nl/randomnumber?key=1234&between=1,100&json": 1,
|
|
62
|
+
"https://api.c99.nl/subdomainfinder?key=fdsa&domain=blacklanternsecurity.com&json": 1,
|
|
63
|
+
"https://api.c99.nl/subdomainfinder?key=6789&domain=blacklanternsecurity.com&json": 1,
|
|
64
|
+
"https://api.c99.nl/subdomainfinder?key=4321&domain=blacklanternsecurity.com&json": 1,
|
|
65
|
+
"https://api.c99.nl/subdomainfinder?key=1234&domain=blacklanternsecurity.com&json": 1,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TestC99AbortThreshold2(TestC99AbortThreshold1):
|
|
70
|
+
targets = ["blacklanternsecurity.com", "evilcorp.com"]
|
|
71
|
+
|
|
72
|
+
async def setup_before_prep(self, module_test):
|
|
73
|
+
await super().setup_before_prep(module_test)
|
|
74
|
+
await module_test.mock_dns(
|
|
75
|
+
{
|
|
76
|
+
"blacklanternsecurity.com": {"A": ["127.0.0.88"]},
|
|
77
|
+
"evilcorp.com": {"A": ["127.0.0.11"]},
|
|
78
|
+
"evilcorp.net": {"A": ["127.0.0.22"]},
|
|
79
|
+
"evilcorp.co.uk": {"A": ["127.0.0.33"]},
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def check(self, module_test, events):
|
|
84
|
+
assert module_test.module.api_failure_abort_threshold == 13
|
|
85
|
+
assert module_test.module.errored is False
|
|
86
|
+
assert module_test.module._api_request_failures == 8
|
|
87
|
+
assert module_test.module.api_retries == 4
|
|
88
|
+
assert {e.data for e in events if e.type == "DNS_NAME"} == {"blacklanternsecurity.com", "evilcorp.com"}
|
|
89
|
+
assert self.url_count == {
|
|
90
|
+
"https://api.c99.nl/randomnumber?key=6789&between=1,100&json": 1,
|
|
91
|
+
"https://api.c99.nl/randomnumber?key=4321&between=1,100&json": 1,
|
|
92
|
+
"https://api.c99.nl/randomnumber?key=1234&between=1,100&json": 1,
|
|
93
|
+
"https://api.c99.nl/subdomainfinder?key=fdsa&domain=blacklanternsecurity.com&json": 1,
|
|
94
|
+
"https://api.c99.nl/subdomainfinder?key=6789&domain=blacklanternsecurity.com&json": 1,
|
|
95
|
+
"https://api.c99.nl/subdomainfinder?key=4321&domain=blacklanternsecurity.com&json": 1,
|
|
96
|
+
"https://api.c99.nl/subdomainfinder?key=1234&domain=blacklanternsecurity.com&json": 1,
|
|
97
|
+
"https://api.c99.nl/subdomainfinder?key=fdsa&domain=evilcorp.com&json": 1,
|
|
98
|
+
"https://api.c99.nl/subdomainfinder?key=6789&domain=evilcorp.com&json": 1,
|
|
99
|
+
"https://api.c99.nl/subdomainfinder?key=4321&domain=evilcorp.com&json": 1,
|
|
100
|
+
"https://api.c99.nl/subdomainfinder?key=1234&domain=evilcorp.com&json": 1,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class TestC99AbortThreshold3(TestC99AbortThreshold2):
|
|
105
|
+
targets = ["blacklanternsecurity.com", "evilcorp.com", "evilcorp.net"]
|
|
106
|
+
|
|
107
|
+
def check(self, module_test, events):
|
|
108
|
+
assert module_test.module.api_failure_abort_threshold == 13
|
|
109
|
+
assert module_test.module.errored is False
|
|
110
|
+
assert module_test.module._api_request_failures == 12
|
|
111
|
+
assert module_test.module.api_retries == 4
|
|
112
|
+
assert {e.data for e in events if e.type == "DNS_NAME"} == {
|
|
113
|
+
"blacklanternsecurity.com",
|
|
114
|
+
"evilcorp.com",
|
|
115
|
+
"evilcorp.net",
|
|
116
|
+
}
|
|
117
|
+
assert self.url_count == {
|
|
118
|
+
"https://api.c99.nl/randomnumber?key=6789&between=1,100&json": 1,
|
|
119
|
+
"https://api.c99.nl/randomnumber?key=4321&between=1,100&json": 1,
|
|
120
|
+
"https://api.c99.nl/randomnumber?key=1234&between=1,100&json": 1,
|
|
121
|
+
"https://api.c99.nl/subdomainfinder?key=fdsa&domain=blacklanternsecurity.com&json": 1,
|
|
122
|
+
"https://api.c99.nl/subdomainfinder?key=6789&domain=blacklanternsecurity.com&json": 1,
|
|
123
|
+
"https://api.c99.nl/subdomainfinder?key=4321&domain=blacklanternsecurity.com&json": 1,
|
|
124
|
+
"https://api.c99.nl/subdomainfinder?key=1234&domain=blacklanternsecurity.com&json": 1,
|
|
125
|
+
"https://api.c99.nl/subdomainfinder?key=fdsa&domain=evilcorp.com&json": 1,
|
|
126
|
+
"https://api.c99.nl/subdomainfinder?key=6789&domain=evilcorp.com&json": 1,
|
|
127
|
+
"https://api.c99.nl/subdomainfinder?key=4321&domain=evilcorp.com&json": 1,
|
|
128
|
+
"https://api.c99.nl/subdomainfinder?key=1234&domain=evilcorp.com&json": 1,
|
|
129
|
+
"https://api.c99.nl/subdomainfinder?key=fdsa&domain=evilcorp.net&json": 1,
|
|
130
|
+
"https://api.c99.nl/subdomainfinder?key=6789&domain=evilcorp.net&json": 1,
|
|
131
|
+
"https://api.c99.nl/subdomainfinder?key=4321&domain=evilcorp.net&json": 1,
|
|
132
|
+
"https://api.c99.nl/subdomainfinder?key=1234&domain=evilcorp.net&json": 1,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class TestC99AbortThreshold4(TestC99AbortThreshold3):
|
|
137
|
+
targets = ["blacklanternsecurity.com", "evilcorp.com", "evilcorp.net", "evilcorp.co.uk"]
|
|
138
|
+
|
|
139
|
+
def check(self, module_test, events):
|
|
140
|
+
assert module_test.module.api_failure_abort_threshold == 13
|
|
141
|
+
assert module_test.module.errored is True
|
|
142
|
+
assert module_test.module._api_request_failures == 13
|
|
143
|
+
assert module_test.module.api_retries == 4
|
|
144
|
+
assert {e.data for e in events if e.type == "DNS_NAME"} == {
|
|
145
|
+
"blacklanternsecurity.com",
|
|
146
|
+
"evilcorp.com",
|
|
147
|
+
"evilcorp.net",
|
|
148
|
+
"evilcorp.co.uk",
|
|
149
|
+
}
|
|
150
|
+
assert len(self.url_count) == 16
|
|
151
|
+
assert all(v == 1 for v in self.url_count.values())
|