bbot 2.3.2.5855rc0__py3-none-any.whl → 2.3.2.5874rc0__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 CHANGED
@@ -1,4 +1,4 @@
1
1
  # version placeholder (replaced by poetry-dynamic-versioning)
2
- __version__ = "v2.3.2.5855rc"
2
+ __version__ = "v2.3.2.5874rc"
3
3
 
4
4
  from .scanner import Scanner, Preset
@@ -154,6 +154,12 @@ class generic_ssrf(BaseModule):
154
154
  produced_events = ["VULNERABILITY"]
155
155
  flags = ["active", "aggressive", "web-thorough"]
156
156
  meta = {"description": "Check for generic SSRFs", "created_date": "2022-07-30", "author": "@liquidsec"}
157
+ options = {
158
+ "skip_dns_interaction": False,
159
+ }
160
+ options_desc = {
161
+ "skip_dns_interaction": "Do not report DNS interactions (only HTTP interaction)",
162
+ }
157
163
  in_scope_only = True
158
164
 
159
165
  deps_apt = ["curl"]
@@ -163,7 +169,7 @@ class generic_ssrf(BaseModule):
163
169
  self.interactsh_subdomain_tags = {}
164
170
  self.parameter_subdomain_tags_map = {}
165
171
  self.severity = None
166
- self.generic_only = self.config.get("generic_only", False)
172
+ self.skip_dns_interaction = self.config.get("skip_dns_interaction", False)
167
173
 
168
174
  if self.scan.config.get("interactsh_disable", False) is False:
169
175
  try:
@@ -191,6 +197,10 @@ class generic_ssrf(BaseModule):
191
197
  await s.test(event)
192
198
 
193
199
  async def interactsh_callback(self, r):
200
+ protocol = r.get("protocol").upper()
201
+ if protocol == "DNS" and self.skip_dns_interaction:
202
+ return
203
+
194
204
  full_id = r.get("full-id", None)
195
205
  subdomain_tag = full_id.split(".")[0]
196
206
 
@@ -204,24 +214,27 @@ class generic_ssrf(BaseModule):
204
214
  matched_severity = match[2]
205
215
  matched_echoed_response = str(match[3])
206
216
 
207
- # Check if any SSRF parameter is in the DNS request
208
217
  triggering_param = self.parameter_subdomain_tags_map.get(subdomain_tag, None)
209
218
  description = f"Out-of-band interaction: [{matched_technique}]"
210
219
  if triggering_param:
211
220
  self.debug(f"Found triggering parameter: {triggering_param}")
212
221
  description += f" [Triggering Parameter: {triggering_param}]"
213
- description += f" [{r.get('protocol').upper()}] Echoed Response: {matched_echoed_response}"
222
+ description += f" [{protocol}] Echoed Response: {matched_echoed_response}"
214
223
 
215
224
  self.debug(f"Emitting event with description: {description}") # Debug the final description
216
225
 
226
+ event_type = "VULNERABILITY" if protocol == "HTTP" else "FINDING"
227
+ event_data = {
228
+ "host": str(matched_event.host),
229
+ "url": matched_event.data,
230
+ "description": description,
231
+ }
232
+ if protocol == "HTTP":
233
+ event_data["severity"] = matched_severity
234
+
217
235
  await self.emit_event(
218
- {
219
- "severity": matched_severity,
220
- "host": str(matched_event.host),
221
- "url": matched_event.data,
222
- "description": description,
223
- },
224
- "VULNERABILITY",
236
+ event_data,
237
+ event_type,
225
238
  matched_event,
226
239
  context=f"{{module}} scanned {matched_event.data} and detected {{event.type}}: {matched_technique}",
227
240
  )
@@ -241,7 +254,7 @@ class generic_ssrf(BaseModule):
241
254
 
242
255
  async def finish(self):
243
256
  if self.scan.config.get("interactsh_disable", False) is False:
244
- await self.helpers.sleep(2)
257
+ await self.helpers.sleep(5)
245
258
  try:
246
259
  for r in await self.interactsh_instance.poll():
247
260
  await self.interactsh_callback(r)
bbot/test/conftest.py CHANGED
@@ -8,6 +8,8 @@ from pathlib import Path
8
8
  from contextlib import suppress
9
9
  from omegaconf import OmegaConf
10
10
  from pytest_httpserver import HTTPServer
11
+ import time
12
+ import queue
11
13
 
12
14
  from bbot.core import CORE
13
15
  from bbot.core.helpers.misc import execute_sync_or_async
@@ -53,6 +55,12 @@ def silence_live_logging():
53
55
  handler.setLevel(logging.CRITICAL)
54
56
 
55
57
 
58
+ def stop_server(server):
59
+ server.stop()
60
+ while server.is_running():
61
+ time.sleep(0.1) # Wait a bit before checking again
62
+
63
+
56
64
  @pytest.fixture
57
65
  def bbot_httpserver():
58
66
  server = HTTPServer(host="127.0.0.1", port=8888, threaded=True)
@@ -61,11 +69,7 @@ def bbot_httpserver():
61
69
  yield server
62
70
 
63
71
  server.clear()
64
- if server.is_running():
65
- server.stop()
66
-
67
- # this is to check if the client has made any request where no
68
- # `assert_request` was called on it from the test
72
+ stop_server(server) # Ensure the server is fully stopped
69
73
 
70
74
  server.check_assertions()
71
75
  server.clear()
@@ -84,11 +88,7 @@ def bbot_httpserver_ssl():
84
88
  yield server
85
89
 
86
90
  server.clear()
87
- if server.is_running():
88
- server.stop()
89
-
90
- # this is to check if the client has made any request where no
91
- # `assert_request` was called on it from the test
91
+ stop_server(server) # Ensure the server is fully stopped
92
92
 
93
93
  server.check_assertions()
94
94
  server.clear()
@@ -129,7 +129,7 @@ class Interactsh_mock:
129
129
  def __init__(self, name):
130
130
  self.name = name
131
131
  self.log = logging.getLogger(f"bbot.interactsh.{self.name}")
132
- self.interactions = []
132
+ self.interactions = asyncio.Queue() # Use an asyncio queue for async access
133
133
  self.correlation_id = "deadbeef-dead-beef-dead-beefdeadbeef"
134
134
  self.stop = False
135
135
  self.poll_task = None
@@ -138,7 +138,7 @@ class Interactsh_mock:
138
138
  self.log.info(f"Mocking interaction to subdomain tag: {subdomain_tag}")
139
139
  if msg is not None:
140
140
  self.log.info(msg)
141
- self.interactions.append(subdomain_tag)
141
+ self.interactions.put_nowait(subdomain_tag) # Add to the thread-safe queue
142
142
 
143
143
  async def register(self, callback=None):
144
144
  if callable(callback):
@@ -146,27 +146,32 @@ class Interactsh_mock:
146
146
  return "fakedomain.fakeinteractsh.com"
147
147
 
148
148
  async def deregister(self, callback=None):
149
+ await asyncio.sleep(1)
149
150
  self.stop = True
150
151
  if self.poll_task is not None:
151
152
  self.poll_task.cancel()
152
- with suppress(BaseException):
153
+ with suppress(asyncio.CancelledError):
153
154
  await self.poll_task
154
155
 
155
156
  async def poll_loop(self, callback=None):
156
157
  while not self.stop:
157
158
  data_list = await self.poll(callback)
158
159
  if not data_list:
159
- await asyncio.sleep(1)
160
+ await asyncio.sleep(0.5)
160
161
  continue
162
+ await asyncio.sleep(1)
163
+ await self.poll(callback)
161
164
 
162
165
  async def poll(self, callback=None):
163
166
  poll_results = []
164
- for subdomain_tag in self.interactions:
165
- result = {"full-id": f"{subdomain_tag}.fakedomain.fakeinteractsh.com", "protocol": "HTTP"}
166
- poll_results.append(result)
167
- if callback is not None:
168
- await execute_sync_or_async(callback, result)
169
- self.interactions = []
167
+ while not self.interactions.empty():
168
+ subdomain_tag = await self.interactions.get() # Get the first element from the asyncio queue
169
+ for protocol in ["HTTP", "DNS"]:
170
+ result = {"full-id": f"{subdomain_tag}.fakedomain.fakeinteractsh.com", "protocol": protocol}
171
+ poll_results.append(result)
172
+ if callback is not None:
173
+ await execute_sync_or_async(callback, result)
174
+ await asyncio.sleep(0.1)
170
175
  return poll_results
171
176
 
172
177
 
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import re
2
3
  from .base import ModuleTestBase
3
4
  from werkzeug.wrappers import Response
@@ -171,7 +172,5 @@ class TestDotnetnuke_blindssrf(ModuleTestBase):
171
172
  if e.type == "VULNERABILITY" and "DotNetNuke Blind-SSRF (CVE 2017-0929)" in e.data["description"]:
172
173
  dnn_dnnimagehandler_blindssrf = True
173
174
 
174
- assert self.interactsh_mock_instance.interactions == []
175
-
176
175
  assert dnn_technology_detection, "DNN Technology Detection Failed"
177
176
  assert dnn_dnnimagehandler_blindssrf, "dnnimagehandler.ashx Blind SSRF Detection Failed"
@@ -1,4 +1,5 @@
1
1
  import re
2
+ import asyncio
2
3
  from werkzeug.wrappers import Response
3
4
 
4
5
  from .base import ModuleTestBase
@@ -23,15 +24,16 @@ class TestGeneric_SSRF(ModuleTestBase):
23
24
  elif request.method == "POST":
24
25
  subdomain_tag = extract_subdomain_tag(request.data.decode())
25
26
  if subdomain_tag:
26
- self.interactsh_mock_instance.mock_interaction(
27
- subdomain_tag, msg=f"{request.method}: {request.data.decode()}"
27
+ asyncio.run(
28
+ self.interactsh_mock_instance.mock_interaction(
29
+ subdomain_tag, msg=f"{request.method}: {request.data.decode()}"
30
+ )
28
31
  )
29
32
 
30
33
  return Response("alive", status=200)
31
34
 
32
35
  async def setup_before_prep(self, module_test):
33
36
  self.interactsh_mock_instance = module_test.mock_interactsh("generic_ssrf")
34
- self.interactsh_mock_instance.mock_interaction("asdf")
35
37
  module_test.monkeypatch.setattr(
36
38
  module_test.scan.helpers, "interactsh", lambda *args, **kwargs: self.interactsh_mock_instance
37
39
  )
@@ -41,6 +43,18 @@ class TestGeneric_SSRF(ModuleTestBase):
41
43
  module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler)
42
44
 
43
45
  def check(self, module_test, events):
46
+ total_vulnerabilities = 0
47
+ total_findings = 0
48
+
49
+ for e in events:
50
+ if e.type == "VULNERABILITY":
51
+ total_vulnerabilities += 1
52
+ elif e.type == "FINDING":
53
+ total_findings += 1
54
+
55
+ assert total_vulnerabilities == 30, "Incorrect number of vulnerabilities detected"
56
+ assert total_findings == 30, "Incorrect number of findings detected"
57
+
44
58
  assert any(
45
59
  e.type == "VULNERABILITY"
46
60
  and "Out-of-band interaction: [Generic SSRF (GET)]"
@@ -55,3 +69,20 @@ class TestGeneric_SSRF(ModuleTestBase):
55
69
  e.type == "VULNERABILITY" and "Out-of-band interaction: [Generic XXE] [HTTP]" in e.data["description"]
56
70
  for e in events
57
71
  ), "Failed to detect Generic SSRF (XXE)"
72
+
73
+
74
+ class TestGeneric_SSRF_httponly(TestGeneric_SSRF):
75
+ config_overrides = {"modules": {"generic_ssrf": {"skip_dns_interaction": True}}}
76
+
77
+ def check(self, module_test, events):
78
+ total_vulnerabilities = 0
79
+ total_findings = 0
80
+
81
+ for e in events:
82
+ if e.type == "VULNERABILITY":
83
+ total_vulnerabilities += 1
84
+ elif e.type == "FINDING":
85
+ total_findings += 1
86
+
87
+ assert total_vulnerabilities == 30, "Incorrect number of vulnerabilities detected"
88
+ assert total_findings == 0, "Incorrect number of findings detected"
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import re
2
3
  from werkzeug.wrappers import Response
3
4
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bbot
3
- Version: 2.3.2.5855rc0
3
+ Version: 2.3.2.5874rc0
4
4
  Summary: OSINT automation for hackers.
5
5
  License: GPL-3.0
6
6
  Keywords: python,cli,automation,osint,threat-intel,intelligence,neo4j,scanner,python-library,hacking,recursion,pentesting,recon,command-line-tool,bugbounty,subdomains,security-tools,subdomain-scanner,osint-framework,attack-surface,subdomain-enumeration,osint-tool
@@ -1,4 +1,4 @@
1
- bbot/__init__.py,sha256=GYangEfD1f4_MA0LLwbhpk2RCgKo7FV5-VUt_2zsS-0,130
1
+ bbot/__init__.py,sha256=NXv4UKb3o37aU0Tj2OzLFNa6wY346sv7D22NpAif7Ds,130
2
2
  bbot/cli.py,sha256=hrzJX07sK3psSQWa461BXFuOxgCA94iztsw8syLdpNw,10830
3
3
  bbot/core/__init__.py,sha256=l255GJE_DvUnWvrRb0J5lG-iMztJ8zVvoweDOfegGtI,46
4
4
  bbot/core/config/__init__.py,sha256=zYNw2Me6tsEr8hOOkLb4BQ97GB7Kis2k--G81S8vofU,342
@@ -102,7 +102,7 @@ bbot/modules/ffuf_shortnames.py,sha256=n6y3FBxgM7CwFBQVSfVYjuQaTOCgjaq2Q2LmdJz-P
102
102
  bbot/modules/filedownload.py,sha256=TOxftfxguaRSEKI8oG79XVRQqUGg1_IhYDYl_Jw9eYc,8694
103
103
  bbot/modules/fingerprintx.py,sha256=rdlR9d64AntAhbS_eJzh8bZCeLPTJPSKdkdKdhH_qAo,3269
104
104
  bbot/modules/fullhunt.py,sha256=zeehQb9akBSbHW9dF4icH8Vfd8LqoTrpIvnQEEMWes8,1311
105
- bbot/modules/generic_ssrf.py,sha256=xsST08_Ka816NmTbUvCC3i_OBZgaEFjDVVQGRuh2tlw,8813
105
+ bbot/modules/generic_ssrf.py,sha256=KFdcHpUV9-Z7oN7emzbirimsNc2xZ_1IFqnsfIkEbcM,9196
106
106
  bbot/modules/git.py,sha256=CMDarsmBemZEzZSeQTzB70XD8IRdwdG39zXpwDdgZbw,1383
107
107
  bbot/modules/git_clone.py,sha256=XFZXx0k97EMY3E5PZzdNvqQzZddOfRMaVp5ol2gk11s,2468
108
108
  bbot/modules/github_codesearch.py,sha256=a-r2vE9N9WyBpFUiKCsg0TK4Qn7DaEGyVRTUKzkDLWA,3641
@@ -239,7 +239,7 @@ bbot/scanner/target.py,sha256=EQwtFZLDeNlqt8JupyBEksqeQ_c_i3NARSWf3mQQC4k,12128
239
239
  bbot/scripts/docs.py,sha256=ZLY9-O6OeEElzOUvTglO5EMkRv1s4aEuxJb2CthCVsI,10782
240
240
  bbot/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
241
241
  bbot/test/bbot_fixtures.py,sha256=JZhqObsSQ5H2RJZCkq4eNaGo6DcxKYMPQ1XFcbE8vQg,9995
242
- bbot/test/conftest.py,sha256=SGyPKXAZNkDclnHs13rfYMq3GH3pqq8yTeGhzfvMuPk,11486
242
+ bbot/test/conftest.py,sha256=dQhpZ-DMkcc0ANiBPvO2Th-QNTecfvMHn0nryL-96i4,11796
243
243
  bbot/test/coverage.cfg,sha256=ko9RacAYsJxWJCL8aEuNtkAOtP9lexYiDbeFWe8Tp8Y,31
244
244
  bbot/test/fastapi_test.py,sha256=9OhOFRyagXTshMsnuzuKIcR4uzS6VW65m7h9KgB4jSA,381
245
245
  bbot/test/owasp_mastg.apk,sha256=Hai_V9JmEJ-aB8Ab9xEaGXXOAfGQudkUvNOuPb75byE,66651
@@ -320,7 +320,7 @@ bbot/test/test_step_2/module_tests/test_module_dnsresolve.py,sha256=15LEcggP_eVY
320
320
  bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py,sha256=8xXSFo0vwKfehIqgF41tbEkL1vbp6RIB8kiO8TSH4NU,2648
321
321
  bbot/test/test_step_2/module_tests/test_module_docker_pull.py,sha256=-JSAo51dS3Ie9RaLBcWK0kfbg8bCPr7mohpFGAwOKPQ,27988
322
322
  bbot/test/test_step_2/module_tests/test_module_dockerhub.py,sha256=9T8CFcFP32MOppUmSVNBUSifnk2kMONqzW_7vvvKdpk,3907
323
- bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py,sha256=voi1C_v7VeaRe_-yzCybO9FUxnFf9qzWkoUY66KYiGI,8114
323
+ bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py,sha256=ps2u_yeDXSkhALGqtg574C5-YvyueRJMjEIoSoTRThc,8064
324
324
  bbot/test/test_step_2/module_tests/test_module_emailformat.py,sha256=cKxBPnEQ4AiRKV_-hSYEE6756ypst3hi6MN0L5RTukY,461
325
325
  bbot/test/test_step_2/module_tests/test_module_emails.py,sha256=bZjtO8N3GG2_g6SUEYprAFLcsi7SlwNPJJ0nODfrWYU,944
326
326
  bbot/test/test_step_2/module_tests/test_module_excavate.py,sha256=eROTkAHYo5lLqJVAVpSl-wprp2-YNQkT9hcaqHEEf7I,43604
@@ -330,7 +330,7 @@ bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py,sha256=1KVSl_g
330
330
  bbot/test/test_step_2/module_tests/test_module_filedownload.py,sha256=ZLPlBVs8CMWofLZAl63zdYMryVdYXykoaxE4jBGED8I,4304
331
331
  bbot/test/test_step_2/module_tests/test_module_fingerprintx.py,sha256=nU3jxbkGcmPYiSzc6thJhNvjAFb4qVxcR7rkOAvjB18,445
332
332
  bbot/test/test_step_2/module_tests/test_module_fullhunt.py,sha256=NblfNHQrE82j-cESvm66hpN-ooKZwR1kEwJDTk_BXac,1946
333
- bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py,sha256=rUs2icFxc-u5GKdzvlpnV1IOa9lcrGVbP5G5cKmn3Yo,2214
333
+ bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py,sha256=ZhfZpH0QTl6_YftGoZzZk6_2x0ZDnWjZ7vNZMTibBHw,3228
334
334
  bbot/test/test_step_2/module_tests/test_module_git.py,sha256=gyBS3vZUWAyatGlcY26mGOYeqXSqJA5pbhJWgTmLqNo,1656
335
335
  bbot/test/test_step_2/module_tests/test_module_git_clone.py,sha256=Mo0Q7bCXcrkGWJc3-u5y4sdfC13ei-qj79aKvEbnkk4,13198
336
336
  bbot/test/test_step_2/module_tests/test_module_github_codesearch.py,sha256=M50xBiGG2EuPGXDJU6uFsSUE-fhqZl3CzYtNdszW7LM,4735
@@ -340,7 +340,7 @@ bbot/test/test_step_2/module_tests/test_module_gitlab.py,sha256=fnwE7BWTU6EQquKd
340
340
  bbot/test/test_step_2/module_tests/test_module_google_playstore.py,sha256=uTRqpAGI9HI-rOk_6jdV44OoSqi0QQQ3aTVzvuV0dtc,3034
341
341
  bbot/test/test_step_2/module_tests/test_module_gowitness.py,sha256=EH3NIMDA3XgZz1yffu-PnRCrlZJODakGPfzgnU7Ls_s,6501
342
342
  bbot/test/test_step_2/module_tests/test_module_hackertarget.py,sha256=ldhNKxGk5fwq87zVptQDyfQ-cn3FzbWvpadKEO3h4ic,609
343
- bbot/test/test_step_2/module_tests/test_module_host_header.py,sha256=w1x0MyKNiUol4hlw7CijhMwEMEL5aBddbZZjOcEgv_k,2672
343
+ bbot/test/test_step_2/module_tests/test_module_host_header.py,sha256=-kod71F8OrWz9GhnXLo06jY6ISnh0EWs95bJTlY36ho,2687
344
344
  bbot/test/test_step_2/module_tests/test_module_http.py,sha256=KhsQvqpVa6zmMa79jV4liv_NAv25wrSaO6h_x0AA12c,2127
345
345
  bbot/test/test_step_2/module_tests/test_module_httpx.py,sha256=kUSJd0eu-e7rj1hnaQyUn5V01JJF7eUlsUjhVAqGvu0,5761
346
346
  bbot/test/test_step_2/module_tests/test_module_hunt.py,sha256=xSnPevrLgFe-umWjvF-X8hOavZCn1s1sClXKM3WBLpE,744
@@ -423,8 +423,8 @@ bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt,sha256=ZSIVebs7ptMvHx
423
423
  bbot/wordlists/top_open_ports_nmap.txt,sha256=LmdFYkfapSxn1pVuQC2LkOIY2hMLgG-Xts7DVtYzweM,42727
424
424
  bbot/wordlists/valid_url_schemes.txt,sha256=0B_VAr9Dv7aYhwi6JSBDU-3M76vNtzN0qEC_RNLo7HE,3310
425
425
  bbot/wordlists/wordninja_dns.txt.gz,sha256=DYHvvfW0TvzrVwyprqODAk4tGOxv5ezNmCPSdPuDUnQ,570241
426
- bbot-2.3.2.5855rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
427
- bbot-2.3.2.5855rc0.dist-info/METADATA,sha256=8nDHIExmXjt2z4dZQim4aPWfY3EC4tz19YqRNSMbMHc,18224
428
- bbot-2.3.2.5855rc0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
429
- bbot-2.3.2.5855rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
430
- bbot-2.3.2.5855rc0.dist-info/RECORD,,
426
+ bbot-2.3.2.5874rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
427
+ bbot-2.3.2.5874rc0.dist-info/METADATA,sha256=FV8caFFR66ZRJY0hZ1VhSwWysNav8XX5x_rIDwAvI1Q,18224
428
+ bbot-2.3.2.5874rc0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
429
+ bbot-2.3.2.5874rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
430
+ bbot-2.3.2.5874rc0.dist-info/RECORD,,