bbot 2.3.0.5546rc0__py3-none-any.whl → 2.3.1.5815rc0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bbot might be problematic. Click here for more details.
- bbot/__init__.py +1 -1
- bbot/cli.py +1 -1
- bbot/core/engine.py +1 -1
- bbot/core/event/base.py +7 -5
- bbot/core/helpers/async_helpers.py +7 -1
- bbot/core/helpers/depsinstaller/installer.py +7 -2
- bbot/core/helpers/diff.py +13 -4
- bbot/core/helpers/dns/brute.py +8 -2
- bbot/core/helpers/dns/engine.py +3 -2
- bbot/core/helpers/ratelimiter.py +8 -2
- bbot/core/helpers/regexes.py +5 -2
- bbot/core/helpers/web/engine.py +1 -1
- bbot/core/helpers/web/web.py +1 -1
- bbot/core/shared_deps.py +14 -0
- bbot/defaults.yml +44 -0
- bbot/modules/ajaxpro.py +64 -37
- bbot/modules/baddns.py +23 -15
- bbot/modules/baddns_direct.py +2 -2
- bbot/modules/badsecrets.py +2 -2
- bbot/modules/base.py +49 -15
- bbot/modules/censys.py +1 -1
- bbot/modules/deadly/dastardly.py +3 -3
- bbot/modules/deadly/nuclei.py +1 -1
- bbot/modules/dehashed.py +2 -2
- bbot/modules/dnsbrute_mutations.py +3 -1
- bbot/modules/docker_pull.py +1 -1
- bbot/modules/dockerhub.py +2 -2
- bbot/modules/dotnetnuke.py +12 -12
- bbot/modules/extractous.py +1 -1
- bbot/modules/ffuf_shortnames.py +107 -48
- bbot/modules/filedownload.py +6 -0
- bbot/modules/generic_ssrf.py +54 -40
- bbot/modules/github_codesearch.py +2 -2
- bbot/modules/github_org.py +16 -20
- bbot/modules/github_workflows.py +6 -2
- bbot/modules/gowitness.py +6 -0
- bbot/modules/hunt.py +1 -1
- bbot/modules/hunterio.py +1 -1
- bbot/modules/iis_shortnames.py +23 -7
- bbot/modules/internal/excavate.py +5 -3
- bbot/modules/internal/unarchive.py +82 -0
- bbot/modules/jadx.py +2 -2
- bbot/modules/output/asset_inventory.py +1 -1
- bbot/modules/output/base.py +1 -1
- bbot/modules/output/discord.py +2 -1
- bbot/modules/output/slack.py +2 -1
- bbot/modules/output/teams.py +10 -25
- bbot/modules/output/web_parameters.py +55 -0
- bbot/modules/paramminer_headers.py +15 -10
- bbot/modules/portfilter.py +41 -0
- bbot/modules/portscan.py +1 -22
- bbot/modules/postman.py +61 -43
- bbot/modules/postman_download.py +10 -147
- bbot/modules/sitedossier.py +1 -1
- bbot/modules/skymem.py +1 -1
- bbot/modules/templates/postman.py +163 -1
- bbot/modules/templates/subdomain_enum.py +1 -1
- bbot/modules/templates/webhook.py +17 -26
- bbot/modules/trufflehog.py +3 -3
- bbot/modules/wappalyzer.py +1 -1
- bbot/modules/zoomeye.py +1 -1
- bbot/presets/kitchen-sink.yml +1 -1
- bbot/presets/nuclei/nuclei-budget.yml +19 -0
- bbot/presets/nuclei/nuclei-intense.yml +28 -0
- bbot/presets/nuclei/nuclei-technology.yml +23 -0
- bbot/presets/nuclei/nuclei.yml +34 -0
- bbot/presets/spider-intense.yml +13 -0
- bbot/scanner/preset/args.py +29 -3
- bbot/scanner/preset/preset.py +43 -24
- bbot/scanner/scanner.py +17 -7
- bbot/test/bbot_fixtures.py +7 -7
- bbot/test/test_step_1/test_bloom_filter.py +2 -2
- bbot/test/test_step_1/test_cli.py +5 -5
- bbot/test/test_step_1/test_dns.py +33 -0
- bbot/test/test_step_1/test_events.py +15 -5
- bbot/test/test_step_1/test_modules_basic.py +21 -21
- bbot/test/test_step_1/test_presets.py +94 -4
- bbot/test/test_step_1/test_regexes.py +13 -13
- bbot/test/test_step_1/test_scan.py +78 -0
- bbot/test/test_step_1/test_web.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_ajaxpro.py +43 -23
- bbot/test/test_step_2/module_tests/test_module_azure_realm.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_baddns.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +6 -6
- bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_dnsbimi.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_dnscaa.py +6 -6
- bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +9 -9
- bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py +12 -12
- bbot/test/test_step_2/module_tests/test_module_excavate.py +15 -15
- bbot/test/test_step_2/module_tests/test_module_extractous.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +8 -8
- bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py +3 -1
- bbot/test/test_step_2/module_tests/test_module_github_codesearch.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_gowitness.py +9 -9
- bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +35 -1
- bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_portfilter.py +48 -0
- bbot/test/test_step_2/module_tests/test_module_postman.py +338 -3
- bbot/test/test_step_2/module_tests/test_module_postman_download.py +4 -161
- bbot/test/test_step_2/module_tests/test_module_securitytxt.py +12 -12
- bbot/test/test_step_2/module_tests/test_module_teams.py +10 -1
- bbot/test/test_step_2/module_tests/test_module_trufflehog.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_unarchive.py +229 -0
- bbot/test/test_step_2/module_tests/test_module_viewdns.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_web_parameters.py +59 -0
- bbot/test/test_step_2/module_tests/test_module_websocket.py +5 -4
- {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/METADATA +7 -7
- {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/RECORD +115 -105
- {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/WHEEL +1 -1
- bbot/wordlists/ffuf_shortname_candidates.txt +0 -107982
- /bbot/presets/{baddns-thorough.yml → baddns-intense.yml} +0 -0
- {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/LICENSE +0 -0
- {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/entry_points.txt +0 -0
|
@@ -4,17 +4,9 @@ from .base import ModuleTestBase
|
|
|
4
4
|
class TestAjaxpro(ModuleTestBase):
|
|
5
5
|
targets = ["http://127.0.0.1:8888"]
|
|
6
6
|
modules_overrides = ["httpx", "ajaxpro"]
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<script type="text/javascript">
|
|
11
|
-
if(typeof AjaxPro != "undefined") AjaxPro.noUtcTime = true;
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<script type="text/javascript" src="/AcmeTest/ajax/AMBusinessFacades.NotificationsAjax,AMBusinessFacades.ashx"></script>
|
|
15
|
-
<script type="text/javascript" src="/AcmeTest/ajax/AMBusinessFacades.ReportingAjax,AMBusinessFacades.ashx"></script>
|
|
16
|
-
<script type="text/javascript" src="/AcmeTest/ajax/AMBusinessFacades.UsersAjax,AMBusinessFacades.ashx"></script>
|
|
17
|
-
<script type="text/javascript" src="/AcmeTest/ajax/FAServerControls.FAPage,FAServerControls.ashx"></script>
|
|
7
|
+
exploit_headers = {"X-Ajaxpro-Method": "AddItem", "Content-Type": "text/json; charset=UTF-8"}
|
|
8
|
+
exploit_response = """
|
|
9
|
+
null; r.error = {"Message":"Constructor on type 'AjaxPro.Services.ICartService' not found.","Type":"System.MissingMethodException"};/*
|
|
18
10
|
"""
|
|
19
11
|
|
|
20
12
|
async def setup_before_prep(self, module_test):
|
|
@@ -28,29 +20,57 @@ class TestAjaxpro(ModuleTestBase):
|
|
|
28
20
|
respond_args = {"status": 404}
|
|
29
21
|
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
30
22
|
|
|
31
|
-
# Simulate HTTP_RESPONSE detection
|
|
32
23
|
expect_args = {"method": "GET", "uri": "/"}
|
|
33
|
-
respond_args = {"response_data":
|
|
24
|
+
respond_args = {"response_data": "alive"}
|
|
25
|
+
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
26
|
+
|
|
27
|
+
# Simulate Vulnerability
|
|
28
|
+
expect_args = {"method": "POST", "uri": "/ajaxpro/AjaxPro.Services.ICartService,AjaxPro.2.ashx"}
|
|
29
|
+
respond_args = {"response_data": self.exploit_response}
|
|
34
30
|
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
35
31
|
|
|
36
32
|
def check(self, module_test, events):
|
|
37
33
|
ajaxpro_url_detection = False
|
|
38
|
-
|
|
34
|
+
ajaxpro_exploit_detection = False
|
|
39
35
|
|
|
40
36
|
for e in events:
|
|
41
37
|
if (
|
|
42
|
-
e.type == "
|
|
43
|
-
and "Ajaxpro
|
|
38
|
+
e.type == "VULNERABILITY"
|
|
39
|
+
and "Ajaxpro Deserialization RCE (CVE-2021-23758)" in e.data["description"]
|
|
40
|
+
and "http://127.0.0.1:8888/ajaxpro/AjaxPro.Services.ICartService,AjaxPro.2.ashx"
|
|
44
41
|
in e.data["description"]
|
|
45
42
|
):
|
|
43
|
+
ajaxpro_exploit_detection = True
|
|
44
|
+
|
|
45
|
+
if e.type == "TECHNOLOGY" and e.data["technology"] == "ajaxpro":
|
|
46
46
|
ajaxpro_url_detection = True
|
|
47
|
-
continue
|
|
48
|
-
if (
|
|
49
|
-
e.type == "FINDING"
|
|
50
|
-
and 'Ajaxpro Detected (Version Unconfirmed) Trigger: [<script src="ajax/AMBusinessFacades.AjaxUtils,AMBusinessFacades.ashx"]'
|
|
51
|
-
):
|
|
52
|
-
ajaxpro_httpresponse_detection = True
|
|
53
|
-
continue
|
|
54
47
|
|
|
55
48
|
assert ajaxpro_url_detection, "Ajaxpro URL probe detection failed"
|
|
49
|
+
assert ajaxpro_exploit_detection, "Ajaxpro Exploit detection failed"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class TestAjaxpro_httpdetect(TestAjaxpro):
|
|
53
|
+
http_response_data = """
|
|
54
|
+
<script src="ajax/AMBusinessFacades.AjaxUtils,AMBusinessFacades.ashx" type="text/javascript"></script><script type='text/javascript'>$(document).ready(function(){if (!(top.hasTouchScreen || (top.home && top.home.hasTouchScreen))){$('#ctl01_userid').trigger('focus').trigger('select');}});</script>
|
|
55
|
+
<script type="text/javascript">
|
|
56
|
+
if(typeof AjaxPro != "undefined") AjaxPro.noUtcTime = true;
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<script type="text/javascript" src="/AcmeTest/ajax/AMBusinessFacades.NotificationsAjax,AMBusinessFacades.ashx"></script>
|
|
60
|
+
<script type="text/javascript" src="/AcmeTest/ajax/AMBusinessFacades.ReportingAjax,AMBusinessFacades.ashx"></script>
|
|
61
|
+
<script type="text/javascript" src="/AcmeTest/ajax/AMBusinessFacades.UsersAjax,AMBusinessFacades.ashx"></script>
|
|
62
|
+
<script type="text/javascript" src="/AcmeTest/ajax/FAServerControls.FAPage,FAServerControls.ashx"></script>
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
async def setup_before_prep(self, module_test):
|
|
66
|
+
# Simulate HTTP_RESPONSE detection
|
|
67
|
+
expect_args = {"method": "GET", "uri": "/"}
|
|
68
|
+
respond_args = {"response_data": self.http_response_data}
|
|
69
|
+
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
70
|
+
|
|
71
|
+
def check(self, module_test, events):
|
|
72
|
+
ajaxpro_httpresponse_detection = False
|
|
73
|
+
for e in events:
|
|
74
|
+
if e.type == "TECHNOLOGY" and e.data["technology"] == "ajaxpro":
|
|
75
|
+
ajaxpro_httpresponse_detection = True
|
|
56
76
|
assert ajaxpro_httpresponse_detection, "Ajaxpro HTTP_RESPONSE detection failed"
|
|
@@ -27,6 +27,6 @@ class TestAzure_Realm(ModuleTestBase):
|
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
def check(self, module_test, events):
|
|
30
|
-
assert any(
|
|
31
|
-
|
|
32
|
-
)
|
|
30
|
+
assert any(e.data == "https://evilcorp.okta.com/app/office365/deadbeef/sso/wsfed/passive" for e in events), (
|
|
31
|
+
"Failed to detect URL"
|
|
32
|
+
)
|
|
@@ -61,7 +61,7 @@ class TestBaddns_cname_signature(BaseTestBaddns):
|
|
|
61
61
|
|
|
62
62
|
def check(self, module_test, events):
|
|
63
63
|
assert any(e for e in events)
|
|
64
|
-
assert any(
|
|
65
|
-
|
|
66
|
-
)
|
|
64
|
+
assert any(e.type == "VULNERABILITY" and "bigcartel.com" in e.data["description"] for e in events), (
|
|
65
|
+
"Failed to emit VULNERABILITY"
|
|
66
|
+
)
|
|
67
67
|
assert any("baddns-cname" in e.tags for e in events), "Failed to add baddns tag"
|
|
@@ -70,14 +70,14 @@ class Bucket_Amazon_Base(ModuleTestBase):
|
|
|
70
70
|
|
|
71
71
|
def check(self, module_test, events):
|
|
72
72
|
# make sure buckets were excavated
|
|
73
|
-
assert any(
|
|
74
|
-
|
|
75
|
-
)
|
|
73
|
+
assert any(e.type == "STORAGE_BUCKET" and str(e.module) == f"cloud_{self.provider}" for e in events), (
|
|
74
|
+
f'bucket not found for module "{self.module_name}"'
|
|
75
|
+
)
|
|
76
76
|
# make sure open buckets were found
|
|
77
77
|
if module_test.module.supports_open_check:
|
|
78
|
-
assert any(
|
|
79
|
-
|
|
80
|
-
)
|
|
78
|
+
assert any(e.type == "FINDING" and str(e.module) == self.module_name for e in events), (
|
|
79
|
+
f'open bucket not found for module "{self.module_name}"'
|
|
80
|
+
)
|
|
81
81
|
for e in events:
|
|
82
82
|
if e.type == "FINDING" and str(e.module) == self.module_name:
|
|
83
83
|
url = e.data.get("url", "")
|
|
@@ -30,6 +30,6 @@ class TestBufferOverrunCommercial(ModuleTestBase):
|
|
|
30
30
|
)
|
|
31
31
|
|
|
32
32
|
def check(self, module_test, events):
|
|
33
|
-
assert any(
|
|
34
|
-
|
|
35
|
-
)
|
|
33
|
+
assert any(e.data == "sub.blacklanternsecurity.com" for e in events), (
|
|
34
|
+
"Failed to detect subdomain for commercial API"
|
|
35
|
+
)
|
|
@@ -58,9 +58,9 @@ class TestCloudCheck(ModuleTestBase):
|
|
|
58
58
|
for event in (aws_event3, other_event1):
|
|
59
59
|
await module.handle_event(event)
|
|
60
60
|
assert "cloud-amazon" not in event.tags, f"{event} was improperly cloud-tagged"
|
|
61
|
-
assert not any(
|
|
62
|
-
|
|
63
|
-
)
|
|
61
|
+
assert not any(t for t in event.tags if t.startswith("cloud-") or t.startswith("cdn-")), (
|
|
62
|
+
f"{event} was improperly cloud-tagged"
|
|
63
|
+
)
|
|
64
64
|
|
|
65
65
|
google_event1 = scan.make_event("asdf.googleapis.com", parent=scan.root_event)
|
|
66
66
|
google_event2 = scan.make_event("asdf.google", parent=scan.root_event)
|
|
@@ -68,9 +68,9 @@ class TestBIMI(ModuleTestBase):
|
|
|
68
68
|
for e in events
|
|
69
69
|
), "Failed to emit RAW_DNS_RECORD"
|
|
70
70
|
|
|
71
|
-
assert any(
|
|
72
|
-
|
|
73
|
-
)
|
|
71
|
+
assert any(e.type == "DNS_NAME" and e.data == "bimi.test.localdomain" for e in events), (
|
|
72
|
+
"Failed to emit DNS_NAME"
|
|
73
|
+
)
|
|
74
74
|
|
|
75
75
|
# This should be filtered by a default BBOT configuration
|
|
76
76
|
assert not any(str(e.data) == "https://nondefault.thirdparty.tld/brand/logo.svg" for e in events)
|
|
@@ -41,16 +41,16 @@ class TestDNSCAA(ModuleTestBase):
|
|
|
41
41
|
def check(self, module_test, events):
|
|
42
42
|
assert any(e.type == "DNS_NAME" and e.data == "comodoca.com" for e in events), "Failed to detect CA DNS name"
|
|
43
43
|
assert any(e.type == "DNS_NAME" and e.data == "digicert.com" for e in events), "Failed to detect CA DNS name"
|
|
44
|
-
assert any(
|
|
45
|
-
|
|
46
|
-
)
|
|
44
|
+
assert any(e.type == "DNS_NAME" and e.data == "letsencrypt.org" for e in events), (
|
|
45
|
+
"Failed to detect CA DNS name"
|
|
46
|
+
)
|
|
47
47
|
assert any(e.type == "DNS_NAME" and e.data == "pki.goog" for e in events), "Failed to detect CA DNS name"
|
|
48
48
|
assert any(
|
|
49
49
|
e.type == "URL_UNVERIFIED" and e.data == "https://caa.blacklanternsecurity.notreal/" for e in events
|
|
50
50
|
), "Failed to detect URL"
|
|
51
|
-
assert any(
|
|
52
|
-
|
|
53
|
-
)
|
|
51
|
+
assert any(e.type == "EMAIL_ADDRESS" and e.data == "caa@blacklanternsecurity.notreal" for e in events), (
|
|
52
|
+
"Failed to detect email address"
|
|
53
|
+
)
|
|
54
54
|
# make sure we're not checking CAA records for out-of-scope hosts
|
|
55
55
|
assert not any(str(e.host) == "caa.comodoca.com" for e in events)
|
|
56
56
|
|
|
@@ -75,21 +75,21 @@ class TestDNSCommonSRV(ModuleTestBase):
|
|
|
75
75
|
and str(e.module) == "dnscommonsrv"
|
|
76
76
|
]
|
|
77
77
|
), "Failed to detect subdomain 2"
|
|
78
|
-
assert 2 == len(
|
|
79
|
-
|
|
80
|
-
)
|
|
81
|
-
assert 1 == len(
|
|
82
|
-
|
|
83
|
-
)
|
|
78
|
+
assert 2 == len([e for e in events if e.type == "DNS_NAME" and e.data == "asdf.blacklanternsecurity.com"]), (
|
|
79
|
+
"Failed to detect subdomain 3"
|
|
80
|
+
)
|
|
81
|
+
assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "api.blacklanternsecurity.com"]), (
|
|
82
|
+
"Failed to detect subdomain 4"
|
|
83
|
+
)
|
|
84
84
|
assert 1 == len(
|
|
85
85
|
[e for e in events if e.type == "DNS_NAME" and e.data == "test.api.blacklanternsecurity.com"]
|
|
86
86
|
), "Failed to detect subdomain 5"
|
|
87
87
|
assert 1 == len(
|
|
88
88
|
[e for e in events if e.type == "DNS_NAME" and e.data == "_msdcs.api.blacklanternsecurity.com"]
|
|
89
89
|
), "Failed to detect subdomain 5"
|
|
90
|
-
assert 1 == len(
|
|
91
|
-
|
|
92
|
-
)
|
|
90
|
+
assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "blacklanternsecurity.com"]), (
|
|
91
|
+
"Failed to detect main domain"
|
|
92
|
+
)
|
|
93
93
|
assert 1 == len(
|
|
94
94
|
[
|
|
95
95
|
e
|
|
@@ -34,21 +34,21 @@ class TestDNSTLSRPT(ModuleTestBase):
|
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
def check(self, module_test, events):
|
|
37
|
-
assert any(
|
|
38
|
-
|
|
39
|
-
)
|
|
40
|
-
assert any(
|
|
41
|
-
|
|
42
|
-
)
|
|
37
|
+
assert any(e.type == "RAW_DNS_RECORD" and e.data["answer"] == raw_smtp_tls_txt for e in events), (
|
|
38
|
+
"Failed to emit RAW_DNS_RECORD"
|
|
39
|
+
)
|
|
40
|
+
assert any(e.type == "DNS_NAME" and e.data == "sub.blacklanternsecurity.notreal" for e in events), (
|
|
41
|
+
"Failed to detect sub-domain"
|
|
42
|
+
)
|
|
43
43
|
assert any(
|
|
44
44
|
e.type == "EMAIL_ADDRESS" and e.data == "tlsrpt@sub.blacklanternsecurity.notreal" for e in events
|
|
45
45
|
), "Failed to detect email address"
|
|
46
|
-
assert any(
|
|
47
|
-
|
|
48
|
-
)
|
|
49
|
-
assert any(
|
|
50
|
-
|
|
51
|
-
)
|
|
46
|
+
assert any(e.type == "EMAIL_ADDRESS" and e.data == "test@on.thirdparty.com" for e in events), (
|
|
47
|
+
"Failed to detect third party email address"
|
|
48
|
+
)
|
|
49
|
+
assert any(e.type == "URL_UNVERIFIED" and e.data == "https://tlspost.example.com/" for e in events), (
|
|
50
|
+
"Failed to detect third party URL"
|
|
51
|
+
)
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
class TestDNSTLSRPTRecursiveRecursion(TestDNSTLSRPT):
|
|
@@ -396,9 +396,9 @@ class TestExcavateSerializationPositive(TestExcavate):
|
|
|
396
396
|
|
|
397
397
|
def check(self, module_test, events):
|
|
398
398
|
for serialize_type in ["Java", "DOTNET", "PHP_Array", "PHP_String", "PHP_Object", "Possible_Compressed"]:
|
|
399
|
-
assert any(
|
|
400
|
-
|
|
401
|
-
)
|
|
399
|
+
assert any(e.type == "FINDING" and serialize_type in e.data["description"] for e in events), (
|
|
400
|
+
f"Did not find {serialize_type} Serialized Object"
|
|
401
|
+
)
|
|
402
402
|
|
|
403
403
|
|
|
404
404
|
class TestExcavateNonHttpScheme(TestExcavate):
|
|
@@ -975,14 +975,14 @@ A href <a href='/donot_detect.js'>Click me</a>"""
|
|
|
975
975
|
assert open(file).read() == self.pdf_data, f"File at {file} does not contain the correct content"
|
|
976
976
|
raw_text_events = [e for e in events if e.type == "RAW_TEXT"]
|
|
977
977
|
assert 1 == len(raw_text_events), "Failed to emit RAW_TEXT event"
|
|
978
|
-
assert (
|
|
979
|
-
raw_text_events[0].data
|
|
980
|
-
)
|
|
978
|
+
assert raw_text_events[0].data == self.extractous_response, (
|
|
979
|
+
f"Text extracted from PDF is incorrect, got {raw_text_events[0].data}"
|
|
980
|
+
)
|
|
981
981
|
email_events = [e for e in events if e.type == "EMAIL_ADDRESS"]
|
|
982
982
|
assert 1 == len(email_events), "Failed to emit EMAIL_ADDRESS event"
|
|
983
|
-
assert (
|
|
984
|
-
email_events[0].data
|
|
985
|
-
)
|
|
983
|
+
assert email_events[0].data == "example@blacklanternsecurity.notreal", (
|
|
984
|
+
f"Email extracted from extractous text is incorrect, got {email_events[0].data}"
|
|
985
|
+
)
|
|
986
986
|
finding_events = [e for e in events if e.type == "FINDING"]
|
|
987
987
|
assert 2 == len(finding_events), "Failed to emit FINDING events"
|
|
988
988
|
assert any(
|
|
@@ -1005,12 +1005,12 @@ A href <a href='/donot_detect.js'>Click me</a>"""
|
|
|
1005
1005
|
), f"Failed to emit serialized event got {finding_events}"
|
|
1006
1006
|
assert finding_events[0].data["path"] == str(file), "File path not included in finding event"
|
|
1007
1007
|
url_events = [e.data for e in events if e.type == "URL_UNVERIFIED"]
|
|
1008
|
-
assert (
|
|
1009
|
-
"
|
|
1010
|
-
)
|
|
1011
|
-
assert (
|
|
1012
|
-
"
|
|
1013
|
-
)
|
|
1008
|
+
assert "https://www.test.notreal/about" in url_events, (
|
|
1009
|
+
f"URL extracted from extractous text is incorrect, got {url_events}"
|
|
1010
|
+
)
|
|
1011
|
+
assert "/donot_detect.js" not in url_events, (
|
|
1012
|
+
f"URL extracted from extractous text is incorrect, got {url_events}"
|
|
1013
|
+
)
|
|
1014
1014
|
|
|
1015
1015
|
|
|
1016
1016
|
class TestExcavateBadURLs(ModuleTestBase):
|
|
@@ -42,9 +42,9 @@ class TestExtractous(ModuleTestBase):
|
|
|
42
42
|
for filesystem_event in filesystem_events:
|
|
43
43
|
file = Path(filesystem_event.data["path"])
|
|
44
44
|
assert file.is_file(), "Destination file doesn't exist"
|
|
45
|
-
assert (
|
|
46
|
-
|
|
47
|
-
)
|
|
45
|
+
assert open(file, "rb").read() == self.pdf_data or open(file, "rb").read() == self.docx_data, (
|
|
46
|
+
f"File at {file} does not contain the correct content"
|
|
47
|
+
)
|
|
48
48
|
raw_text_events = [e for e in events if e.type == "RAW_TEXT"]
|
|
49
49
|
assert 2 == len(raw_text_events), "Failed to emit RAW_TEXT event"
|
|
50
50
|
for raw_text_event in raw_text_events:
|
|
@@ -31,7 +31,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
31
31
|
"URL_HINT",
|
|
32
32
|
parent_event,
|
|
33
33
|
module="iis_shortnames",
|
|
34
|
-
tags=["shortname-
|
|
34
|
+
tags=["shortname-endpoint"],
|
|
35
35
|
)
|
|
36
36
|
)
|
|
37
37
|
seed_events.append(
|
|
@@ -40,7 +40,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
40
40
|
"URL_HINT",
|
|
41
41
|
parent_event,
|
|
42
42
|
module="iis_shortnames",
|
|
43
|
-
tags=["shortname-
|
|
43
|
+
tags=["shortname-endpoint"],
|
|
44
44
|
)
|
|
45
45
|
)
|
|
46
46
|
seed_events.append(
|
|
@@ -49,7 +49,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
49
49
|
"URL_HINT",
|
|
50
50
|
parent_event,
|
|
51
51
|
module="iis_shortnames",
|
|
52
|
-
tags=["shortname-
|
|
52
|
+
tags=["shortname-endpoint"],
|
|
53
53
|
)
|
|
54
54
|
)
|
|
55
55
|
seed_events.append(
|
|
@@ -58,7 +58,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
58
58
|
"URL_HINT",
|
|
59
59
|
parent_event,
|
|
60
60
|
module="iis_shortnames",
|
|
61
|
-
tags=["shortname-
|
|
61
|
+
tags=["shortname-endpoint"],
|
|
62
62
|
)
|
|
63
63
|
)
|
|
64
64
|
seed_events.append(
|
|
@@ -67,7 +67,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
67
67
|
"URL_HINT",
|
|
68
68
|
parent_event,
|
|
69
69
|
module="iis_shortnames",
|
|
70
|
-
tags=["shortname-
|
|
70
|
+
tags=["shortname-endpoint"],
|
|
71
71
|
)
|
|
72
72
|
)
|
|
73
73
|
seed_events.append(
|
|
@@ -76,7 +76,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
76
76
|
"URL_HINT",
|
|
77
77
|
parent_event,
|
|
78
78
|
module="iis_shortnames",
|
|
79
|
-
tags=["shortname-
|
|
79
|
+
tags=["shortname-endpoint"],
|
|
80
80
|
)
|
|
81
81
|
)
|
|
82
82
|
seed_events.append(
|
|
@@ -139,7 +139,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
139
139
|
"URL_HINT",
|
|
140
140
|
parent_event,
|
|
141
141
|
module="iis_shortnames",
|
|
142
|
-
tags=["shortname-
|
|
142
|
+
tags=["shortname-endpoint"],
|
|
143
143
|
)
|
|
144
144
|
)
|
|
145
145
|
module_test.scan.target.seeds.events = set(seed_events)
|
|
@@ -191,7 +191,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
191
191
|
prefix_detection = True
|
|
192
192
|
if e.data == "http://127.0.0.1:8888/abcconsole.aspx":
|
|
193
193
|
delimiter_detection = True
|
|
194
|
-
if e.data == "http://127.0.0.1:8888/
|
|
194
|
+
if e.data == "http://127.0.0.1:8888/adm_directory/":
|
|
195
195
|
directory_delimiter_detection = True
|
|
196
196
|
if e.data == "http://127.0.0.1:8888/xyzdirectory/":
|
|
197
197
|
prefix_delimiter_detection = True
|
|
@@ -42,7 +42,9 @@ class TestGeneric_SSRF(ModuleTestBase):
|
|
|
42
42
|
|
|
43
43
|
def check(self, module_test, events):
|
|
44
44
|
assert any(
|
|
45
|
-
e.type == "VULNERABILITY"
|
|
45
|
+
e.type == "VULNERABILITY"
|
|
46
|
+
and "Out-of-band interaction: [Generic SSRF (GET)]"
|
|
47
|
+
and "[Triggering Parameter: Dest]" in e.data["description"]
|
|
46
48
|
for e in events
|
|
47
49
|
), "Failed to detect Generic SSRF (GET)"
|
|
48
50
|
assert any(
|
|
@@ -99,6 +99,6 @@ Gnl54dJHT+EhlfY=
|
|
|
99
99
|
if e.type == "HTTP_RESPONSE" and e.data["url"] == self.github_file_url and e.scope_distance == 2
|
|
100
100
|
]
|
|
101
101
|
), "Failed to visit URL"
|
|
102
|
-
assert [
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
assert [e for e in events if e.type == "FINDING" and str(e.module) == "trufflehog"], (
|
|
103
|
+
"Failed to find secret in repo file"
|
|
104
|
+
)
|
|
@@ -46,15 +46,15 @@ class TestGowitness(ModuleTestBase):
|
|
|
46
46
|
def check(self, module_test, events):
|
|
47
47
|
webscreenshots = [e for e in events if e.type == "WEBSCREENSHOT"]
|
|
48
48
|
assert webscreenshots, "failed to raise WEBSCREENSHOT events"
|
|
49
|
-
assert not any(
|
|
50
|
-
"blob
|
|
51
|
-
)
|
|
49
|
+
assert not any("blob" in e.data for e in webscreenshots), (
|
|
50
|
+
"blob was included in WEBSCREENSHOT data when it shouldn't have been"
|
|
51
|
+
)
|
|
52
52
|
|
|
53
53
|
screenshots_path = self.home_dir / "scans" / module_test.scan.name / "gowitness" / "screenshots"
|
|
54
54
|
screenshots = list(screenshots_path.glob("*.png"))
|
|
55
|
-
assert (
|
|
56
|
-
len(screenshots)
|
|
57
|
-
)
|
|
55
|
+
assert len(screenshots) == 1, (
|
|
56
|
+
f"{len(screenshots):,} .png files found at {screenshots_path}, should have been 1"
|
|
57
|
+
)
|
|
58
58
|
assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/"])
|
|
59
59
|
assert 1 == len(
|
|
60
60
|
[e for e in events if e.type == "URL_UNVERIFIED" and e.data == "https://fonts.googleapis.com/"]
|
|
@@ -75,9 +75,9 @@ class TestGowitness_Social(TestGowitness):
|
|
|
75
75
|
def check(self, module_test, events):
|
|
76
76
|
screenshots_path = self.home_dir / "scans" / module_test.scan.name / "gowitness" / "screenshots"
|
|
77
77
|
screenshots = list(screenshots_path.glob("*.png"))
|
|
78
|
-
assert (
|
|
79
|
-
len(screenshots)
|
|
80
|
-
)
|
|
78
|
+
assert len(screenshots) == 2, (
|
|
79
|
+
f"{len(screenshots):,} .png files found at {screenshots_path}, should have been 2"
|
|
80
|
+
)
|
|
81
81
|
assert 2 == len([e for e in events if e.type == "WEBSCREENSHOT"])
|
|
82
82
|
assert 1 == len(
|
|
83
83
|
[
|
|
@@ -52,7 +52,7 @@ class TestIIS_Shortnames(ModuleTestBase):
|
|
|
52
52
|
vulnerabilityEmitted = False
|
|
53
53
|
url_hintEmitted = False
|
|
54
54
|
for e in events:
|
|
55
|
-
if e.type == "VULNERABILITY":
|
|
55
|
+
if e.type == "VULNERABILITY" and "iis-magic-url" not in e.tags:
|
|
56
56
|
vulnerabilityEmitted = True
|
|
57
57
|
if e.type == "URL_HINT" and e.data == "http://127.0.0.1:8888/BLSHAX~1":
|
|
58
58
|
url_hintEmitted = True
|
|
@@ -193,9 +193,12 @@ class TestParamminer_Getparams_finish(Paramminer_Headers):
|
|
|
193
193
|
class TestParamminer_Getparams_xmlspeculative(Paramminer_Headers):
|
|
194
194
|
targets = ["http://127.0.0.1:8888/"]
|
|
195
195
|
modules_overrides = ["httpx", "excavate", "paramminer_getparams"]
|
|
196
|
-
config_overrides = {
|
|
196
|
+
config_overrides = {
|
|
197
|
+
"modules": {"paramminer_getparams": {"wordlist": tempwordlist(["data", "common"]), "recycle_words": False}}
|
|
198
|
+
}
|
|
197
199
|
getparam_extract_xml = """
|
|
198
200
|
<data>
|
|
201
|
+
<junkparameter>1</junkparameter>
|
|
199
202
|
<obscureParameter>1</obscureParameter>
|
|
200
203
|
<common>1</common>
|
|
201
204
|
</data>
|
|
@@ -242,3 +245,34 @@ class TestParamminer_Getparams_xmlspeculative(Paramminer_Headers):
|
|
|
242
245
|
|
|
243
246
|
assert excavate_discovered_speculative, "Excavate failed to discover speculative xml parameter"
|
|
244
247
|
assert paramminer_used_speculative, "Paramminer failed to confirm speculative GET parameter"
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class TestParamminer_Getparams_filter_static(TestParamminer_Getparams_finish):
|
|
251
|
+
targets = ["http://127.0.0.1:8888/test1.php", "http://127.0.0.1:8888/test2.pdf"]
|
|
252
|
+
|
|
253
|
+
test_1_html = """
|
|
254
|
+
<html><a href="/test2.pdf?abcd1234=foo">paramstest2</a></html>
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
def check(self, module_test, events):
|
|
258
|
+
found_hidden_getparam_recycled = False
|
|
259
|
+
emitted_excavate_paramminer_duplicate = False
|
|
260
|
+
|
|
261
|
+
for e in events:
|
|
262
|
+
if e.type == "WEB_PARAMETER":
|
|
263
|
+
if (
|
|
264
|
+
"http://127.0.0.1:8888/test1.php" in e.data["url"]
|
|
265
|
+
and "[Paramminer] Getparam: [abcd1234] Reasons: [body] Reflection: [False]"
|
|
266
|
+
in e.data["description"]
|
|
267
|
+
):
|
|
268
|
+
found_hidden_getparam_recycled = True
|
|
269
|
+
|
|
270
|
+
if (
|
|
271
|
+
"http://127.0.0.1:8888/test2.pdf" in e.data["url"]
|
|
272
|
+
and "[Paramminer] Getparam: [abcd1234] Reasons: [body] Reflection: [False]"
|
|
273
|
+
in e.data["description"]
|
|
274
|
+
):
|
|
275
|
+
emitted_excavate_paramminer_duplicate = True
|
|
276
|
+
|
|
277
|
+
assert found_hidden_getparam_recycled, "Failed to find hidden GET parameter"
|
|
278
|
+
assert not emitted_excavate_paramminer_duplicate, "Paramminer emitted parameter for static URL"
|
|
@@ -150,6 +150,6 @@ class TestParamminer_Headers_extract_norecycle(TestParamminer_Headers_extract):
|
|
|
150
150
|
if "HTTP Extracted Parameter [foo] (HTML Tags Submodule)" in e.data["description"]:
|
|
151
151
|
excavate_extracted_web_parameter = True
|
|
152
152
|
|
|
153
|
-
assert (
|
|
154
|
-
|
|
155
|
-
)
|
|
153
|
+
assert not excavate_extracted_web_parameter, (
|
|
154
|
+
"Excavate extract WEB_PARAMETER despite disabling parameter extraction"
|
|
155
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from .base import ModuleTestBase
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestPortfilter_disabled(ModuleTestBase):
|
|
5
|
+
modules_overrides = []
|
|
6
|
+
|
|
7
|
+
async def setup_before_prep(self, module_test):
|
|
8
|
+
from bbot.modules.base import BaseModule
|
|
9
|
+
|
|
10
|
+
class DummyModule(BaseModule):
|
|
11
|
+
_name = "dummy_module"
|
|
12
|
+
watched_events = ["DNS_NAME"]
|
|
13
|
+
|
|
14
|
+
async def handle_event(self, event):
|
|
15
|
+
if event.type == "DNS_NAME" and event.data == "blacklanternsecurity.com":
|
|
16
|
+
await self.emit_event(
|
|
17
|
+
"www.blacklanternsecurity.com:443",
|
|
18
|
+
"OPEN_TCP_PORT",
|
|
19
|
+
parent=event,
|
|
20
|
+
tags=["cdn-ip", "cdn-amazon"],
|
|
21
|
+
)
|
|
22
|
+
# when portfilter is enabled, this should be filtered out
|
|
23
|
+
await self.emit_event(
|
|
24
|
+
"www.blacklanternsecurity.com:8080",
|
|
25
|
+
"OPEN_TCP_PORT",
|
|
26
|
+
parent=event,
|
|
27
|
+
tags=["cdn-ip", "cdn-amazon"],
|
|
28
|
+
)
|
|
29
|
+
await self.emit_event("www.blacklanternsecurity.com:21", "OPEN_TCP_PORT", parent=event)
|
|
30
|
+
|
|
31
|
+
module_test.scan.modules["dummy_module"] = DummyModule(module_test.scan)
|
|
32
|
+
|
|
33
|
+
def check(self, module_test, events):
|
|
34
|
+
open_ports = {event.data for event in events if event.type == "OPEN_TCP_PORT"}
|
|
35
|
+
assert open_ports == {
|
|
36
|
+
"www.blacklanternsecurity.com:443",
|
|
37
|
+
"www.blacklanternsecurity.com:8080",
|
|
38
|
+
"www.blacklanternsecurity.com:21",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TestPortfilter_enabled(TestPortfilter_disabled):
|
|
43
|
+
modules_overrides = ["portfilter"]
|
|
44
|
+
|
|
45
|
+
def check(self, module_test, events):
|
|
46
|
+
open_ports = {event.data for event in events if event.type == "OPEN_TCP_PORT"}
|
|
47
|
+
# we should be missing the 8080 port because it's a CDN and not in portfilter's allowed list of open ports
|
|
48
|
+
assert open_ports == {"www.blacklanternsecurity.com:443", "www.blacklanternsecurity.com:21"}
|