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.

Files changed (116) hide show
  1. bbot/__init__.py +1 -1
  2. bbot/cli.py +1 -1
  3. bbot/core/engine.py +1 -1
  4. bbot/core/event/base.py +7 -5
  5. bbot/core/helpers/async_helpers.py +7 -1
  6. bbot/core/helpers/depsinstaller/installer.py +7 -2
  7. bbot/core/helpers/diff.py +13 -4
  8. bbot/core/helpers/dns/brute.py +8 -2
  9. bbot/core/helpers/dns/engine.py +3 -2
  10. bbot/core/helpers/ratelimiter.py +8 -2
  11. bbot/core/helpers/regexes.py +5 -2
  12. bbot/core/helpers/web/engine.py +1 -1
  13. bbot/core/helpers/web/web.py +1 -1
  14. bbot/core/shared_deps.py +14 -0
  15. bbot/defaults.yml +44 -0
  16. bbot/modules/ajaxpro.py +64 -37
  17. bbot/modules/baddns.py +23 -15
  18. bbot/modules/baddns_direct.py +2 -2
  19. bbot/modules/badsecrets.py +2 -2
  20. bbot/modules/base.py +49 -15
  21. bbot/modules/censys.py +1 -1
  22. bbot/modules/deadly/dastardly.py +3 -3
  23. bbot/modules/deadly/nuclei.py +1 -1
  24. bbot/modules/dehashed.py +2 -2
  25. bbot/modules/dnsbrute_mutations.py +3 -1
  26. bbot/modules/docker_pull.py +1 -1
  27. bbot/modules/dockerhub.py +2 -2
  28. bbot/modules/dotnetnuke.py +12 -12
  29. bbot/modules/extractous.py +1 -1
  30. bbot/modules/ffuf_shortnames.py +107 -48
  31. bbot/modules/filedownload.py +6 -0
  32. bbot/modules/generic_ssrf.py +54 -40
  33. bbot/modules/github_codesearch.py +2 -2
  34. bbot/modules/github_org.py +16 -20
  35. bbot/modules/github_workflows.py +6 -2
  36. bbot/modules/gowitness.py +6 -0
  37. bbot/modules/hunt.py +1 -1
  38. bbot/modules/hunterio.py +1 -1
  39. bbot/modules/iis_shortnames.py +23 -7
  40. bbot/modules/internal/excavate.py +5 -3
  41. bbot/modules/internal/unarchive.py +82 -0
  42. bbot/modules/jadx.py +2 -2
  43. bbot/modules/output/asset_inventory.py +1 -1
  44. bbot/modules/output/base.py +1 -1
  45. bbot/modules/output/discord.py +2 -1
  46. bbot/modules/output/slack.py +2 -1
  47. bbot/modules/output/teams.py +10 -25
  48. bbot/modules/output/web_parameters.py +55 -0
  49. bbot/modules/paramminer_headers.py +15 -10
  50. bbot/modules/portfilter.py +41 -0
  51. bbot/modules/portscan.py +1 -22
  52. bbot/modules/postman.py +61 -43
  53. bbot/modules/postman_download.py +10 -147
  54. bbot/modules/sitedossier.py +1 -1
  55. bbot/modules/skymem.py +1 -1
  56. bbot/modules/templates/postman.py +163 -1
  57. bbot/modules/templates/subdomain_enum.py +1 -1
  58. bbot/modules/templates/webhook.py +17 -26
  59. bbot/modules/trufflehog.py +3 -3
  60. bbot/modules/wappalyzer.py +1 -1
  61. bbot/modules/zoomeye.py +1 -1
  62. bbot/presets/kitchen-sink.yml +1 -1
  63. bbot/presets/nuclei/nuclei-budget.yml +19 -0
  64. bbot/presets/nuclei/nuclei-intense.yml +28 -0
  65. bbot/presets/nuclei/nuclei-technology.yml +23 -0
  66. bbot/presets/nuclei/nuclei.yml +34 -0
  67. bbot/presets/spider-intense.yml +13 -0
  68. bbot/scanner/preset/args.py +29 -3
  69. bbot/scanner/preset/preset.py +43 -24
  70. bbot/scanner/scanner.py +17 -7
  71. bbot/test/bbot_fixtures.py +7 -7
  72. bbot/test/test_step_1/test_bloom_filter.py +2 -2
  73. bbot/test/test_step_1/test_cli.py +5 -5
  74. bbot/test/test_step_1/test_dns.py +33 -0
  75. bbot/test/test_step_1/test_events.py +15 -5
  76. bbot/test/test_step_1/test_modules_basic.py +21 -21
  77. bbot/test/test_step_1/test_presets.py +94 -4
  78. bbot/test/test_step_1/test_regexes.py +13 -13
  79. bbot/test/test_step_1/test_scan.py +78 -0
  80. bbot/test/test_step_1/test_web.py +4 -4
  81. bbot/test/test_step_2/module_tests/test_module_ajaxpro.py +43 -23
  82. bbot/test/test_step_2/module_tests/test_module_azure_realm.py +3 -3
  83. bbot/test/test_step_2/module_tests/test_module_baddns.py +3 -3
  84. bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +6 -6
  85. bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py +3 -3
  86. bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +3 -3
  87. bbot/test/test_step_2/module_tests/test_module_dnsbimi.py +3 -3
  88. bbot/test/test_step_2/module_tests/test_module_dnscaa.py +6 -6
  89. bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +9 -9
  90. bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py +12 -12
  91. bbot/test/test_step_2/module_tests/test_module_excavate.py +15 -15
  92. bbot/test/test_step_2/module_tests/test_module_extractous.py +3 -3
  93. bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +8 -8
  94. bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py +3 -1
  95. bbot/test/test_step_2/module_tests/test_module_github_codesearch.py +3 -3
  96. bbot/test/test_step_2/module_tests/test_module_gowitness.py +9 -9
  97. bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py +1 -1
  98. bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +35 -1
  99. bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +3 -3
  100. bbot/test/test_step_2/module_tests/test_module_portfilter.py +48 -0
  101. bbot/test/test_step_2/module_tests/test_module_postman.py +338 -3
  102. bbot/test/test_step_2/module_tests/test_module_postman_download.py +4 -161
  103. bbot/test/test_step_2/module_tests/test_module_securitytxt.py +12 -12
  104. bbot/test/test_step_2/module_tests/test_module_teams.py +10 -1
  105. bbot/test/test_step_2/module_tests/test_module_trufflehog.py +1 -1
  106. bbot/test/test_step_2/module_tests/test_module_unarchive.py +229 -0
  107. bbot/test/test_step_2/module_tests/test_module_viewdns.py +3 -3
  108. bbot/test/test_step_2/module_tests/test_module_web_parameters.py +59 -0
  109. bbot/test/test_step_2/module_tests/test_module_websocket.py +5 -4
  110. {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/METADATA +7 -7
  111. {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/RECORD +115 -105
  112. {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/WHEEL +1 -1
  113. bbot/wordlists/ffuf_shortname_candidates.txt +0 -107982
  114. /bbot/presets/{baddns-thorough.yml → baddns-intense.yml} +0 -0
  115. {bbot-2.3.0.5546rc0.dist-info → bbot-2.3.1.5815rc0.dist-info}/LICENSE +0 -0
  116. {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
- http_response_data = """
9
- <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>
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": self.http_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
- ajaxpro_httpresponse_detection = False
34
+ ajaxpro_exploit_detection = False
39
35
 
40
36
  for e in events:
41
37
  if (
42
- e.type == "FINDING"
43
- and "Ajaxpro Detected (Version Unconfirmed) Trigger: [http://127.0.0.1:8888/ajaxpro/whatever.ashx]"
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
- e.data == "https://evilcorp.okta.com/app/office365/deadbeef/sso/wsfed/passive" for e in events
32
- ), "Failed to detect URL"
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
- e.type == "VULNERABILITY" and "bigcartel.com" in e.data["description"] for e in events
66
- ), "Failed to emit VULNERABILITY"
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
- e.type == "STORAGE_BUCKET" and str(e.module) == f"cloud_{self.provider}" for e in events
75
- ), f'bucket not found for module "{self.module_name}"'
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
- e.type == "FINDING" and str(e.module) == self.module_name for e in events
80
- ), f'open bucket not found for module "{self.module_name}"'
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
- e.data == "sub.blacklanternsecurity.com" for e in events
35
- ), "Failed to detect subdomain for commercial API"
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
- t for t in event.tags if t.startswith("cloud-") or t.startswith("cdn-")
63
- ), f"{event} was improperly cloud-tagged"
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
- e.type == "DNS_NAME" and e.data == "bimi.test.localdomain" for e in events
73
- ), "Failed to emit DNS_NAME"
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
- e.type == "DNS_NAME" and e.data == "letsencrypt.org" for e in events
46
- ), "Failed to detect CA DNS name"
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
- e.type == "EMAIL_ADDRESS" and e.data == "caa@blacklanternsecurity.notreal" for e in events
53
- ), "Failed to detect email address"
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
- [e for e in events if e.type == "DNS_NAME" and e.data == "asdf.blacklanternsecurity.com"]
80
- ), "Failed to detect subdomain 3"
81
- assert 1 == len(
82
- [e for e in events if e.type == "DNS_NAME" and e.data == "api.blacklanternsecurity.com"]
83
- ), "Failed to detect subdomain 4"
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
- [e for e in events if e.type == "DNS_NAME" and e.data == "blacklanternsecurity.com"]
92
- ), "Failed to detect main domain"
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
- e.type == "RAW_DNS_RECORD" and e.data["answer"] == raw_smtp_tls_txt for e in events
39
- ), "Failed to emit RAW_DNS_RECORD"
40
- assert any(
41
- e.type == "DNS_NAME" and e.data == "sub.blacklanternsecurity.notreal" for e in events
42
- ), "Failed to detect sub-domain"
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
- e.type == "EMAIL_ADDRESS" and e.data == "test@on.thirdparty.com" for e in events
48
- ), "Failed to detect third party email address"
49
- assert any(
50
- e.type == "URL_UNVERIFIED" and e.data == "https://tlspost.example.com/" for e in events
51
- ), "Failed to detect third party URL"
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
- e.type == "FINDING" and serialize_type in e.data["description"] for e in events
401
- ), f"Did not find {serialize_type} Serialized Object"
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 == self.extractous_response
980
- ), f"Text extracted from PDF is incorrect, got {raw_text_events[0].data}"
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 == "example@blacklanternsecurity.notreal"
985
- ), f"Email extracted from extractous text is incorrect, got {email_events[0].data}"
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
- "https://www.test.notreal/about" in url_events
1010
- ), f"URL extracted from extractous text is incorrect, got {url_events}"
1011
- assert (
1012
- "/donot_detect.js" not in url_events
1013
- ), f"URL extracted from extractous text is incorrect, got {url_events}"
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
- open(file, "rb").read() == self.pdf_data or open(file, "rb").read() == self.docx_data
47
- ), f"File at {file} does not contain the correct content"
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-file"],
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-file"],
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-file"],
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-file"],
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-file"],
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-file"],
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-file"],
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/abcconsole.aspx":
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" and "Out-of-band interaction: [Generic SSRF (GET)]" in e.data["description"]
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
- e for e in events if e.type == "FINDING" and str(e.module) == "trufflehog"
104
- ], "Failed to find secret in repo file"
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" in e.data for e in webscreenshots
51
- ), "blob was included in WEBSCREENSHOT data when it shouldn't have been"
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) == 1
57
- ), f"{len(screenshots):,} .png files found at {screenshots_path}, should have been 1"
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) == 2
80
- ), f"{len(screenshots):,} .png files found at {screenshots_path}, should have been 2"
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 = {"modules": {"paramminer_getparams": {"wordlist": tempwordlist([]), "recycle_words": False}}}
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
- not excavate_extracted_web_parameter
155
- ), "Excavate extract WEB_PARAMETER despite disabling parameter extraction"
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"}