bbot 2.7.0.6962rc0__py3-none-any.whl → 2.7.0.6989rc0__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,5 +1,5 @@
1
1
  # version placeholder (replaced by poetry-dynamic-versioning)
2
- __version__ = "v2.7.0.6962rc"
2
+ __version__ = "v2.7.0.6989rc"
3
3
 
4
4
  from .scanner import Scanner, Preset
5
5
 
@@ -9,7 +9,7 @@ from .misc import rm_at_exit
9
9
  log = logging.getLogger("bbot.core.helpers.files")
10
10
 
11
11
 
12
- def tempfile(self, content, pipe=True):
12
+ def tempfile(self, content, pipe=True, extension=None):
13
13
  """
14
14
  Creates a temporary file or named pipe and populates it with content.
15
15
 
@@ -29,7 +29,7 @@ def tempfile(self, content, pipe=True):
29
29
  >>> tempfile(["Another", "temp", "file"], pipe=False)
30
30
  '/home/user/.bbot/temp/someotherfile'
31
31
  """
32
- filename = self.temp_filename()
32
+ filename = self.temp_filename(extension)
33
33
  rm_at_exit(filename)
34
34
  try:
35
35
  if type(content) not in (set, list, tuple):
bbot/defaults.yml CHANGED
@@ -187,8 +187,10 @@ url_extension_blacklist:
187
187
  - mov
188
188
  - flv
189
189
  - webm
190
- # Distribute URLs with these extensions only to httpx (these are omitted from output)
191
- url_extension_httpx_only:
190
+
191
+ # URLs with these extensions are not distributed to modules unless the module opts in via `accept_url_special = True`
192
+ # They are also excluded from output. If you want to see them in output, remove them from this list.
193
+ url_extension_special:
192
194
  - js
193
195
 
194
196
  # These url extensions are almost always static, so we exclude them from modules that fuzz things
bbot/modules/base.py CHANGED
@@ -53,6 +53,8 @@ class BaseModule:
53
53
 
54
54
  in_scope_only (bool): Accept only explicitly in-scope events, regardless of the scan's search distance. Default is False.
55
55
 
56
+ accept_url_special (bool): Accept "special" URLs not typically distributed to web modules, e.g. JS URLs. Default is False.
57
+
56
58
  options (Dict): Customizable options for the module, e.g., {"api_key": ""}. Empty dict by default.
57
59
 
58
60
  options_desc (Dict): Descriptions for options, e.g., {"api_key": "API Key"}. Empty dict by default.
@@ -97,7 +99,7 @@ class BaseModule:
97
99
  scope_distance_modifier = 0
98
100
  target_only = False
99
101
  in_scope_only = False
100
-
102
+ accept_url_special = False
101
103
  _module_threads = 1
102
104
  _batch_size = 1
103
105
 
@@ -785,10 +787,14 @@ class BaseModule:
785
787
  if "target" not in event.tags:
786
788
  return False, "it did not meet target_only filter criteria"
787
789
 
788
- # exclude certain URLs (e.g. javascript):
789
- # TODO: revisit this after httpx rework
790
- if event.type.startswith("URL") and self.name != "httpx" and "httpx-only" in event.tags:
791
- return False, "its extension was listed in url_extension_httpx_only"
790
+ # limit js URLs to modules that opt in to receive them
791
+ if (not self.accept_url_special) and event.type.startswith("URL"):
792
+ extension = getattr(event, "url_extension", "")
793
+ if extension in self.scan.url_extension_special:
794
+ return (
795
+ False,
796
+ f"it is a special URL (extension {extension}) but the module does not opt in to receive special URLs",
797
+ )
792
798
 
793
799
  return True, "precheck succeeded"
794
800
 
@@ -27,7 +27,6 @@ class graphql_introspection(BaseModule):
27
27
  self.output_dir = Path(output_folder) / "graphql-schemas"
28
28
  else:
29
29
  self.output_dir = self.scan.home / "graphql-schemas"
30
- self.helpers.mkdir(self.output_dir)
31
30
  return True
32
31
 
33
32
  async def filter_event(self, event):
@@ -128,6 +127,7 @@ fragment TypeRef on __Type {
128
127
  self.debug(f"Failed to parse JSON for {url}")
129
128
  continue
130
129
  if response_json.get("data", {}).get("__schema", {}).get("types", []):
130
+ self.helpers.mkdir(self.output_dir)
131
131
  filename = f"schema-{self.helpers.tagify(url)}.json"
132
132
  filename = self.output_dir / filename
133
133
  with open(filename, "w") as f:
bbot/modules/httpx.py CHANGED
@@ -50,6 +50,8 @@ class httpx(BaseModule):
50
50
  _shuffle_incoming_queue = False
51
51
  _batch_size = 500
52
52
  _priority = 2
53
+ # accept Javascript URLs
54
+ accept_url_special = True
53
55
 
54
56
  async def setup(self):
55
57
  self.threads = self.config.get("threads", 50)
@@ -38,11 +38,6 @@ class BaseOutputModule(BaseModule):
38
38
  if self._is_graph_important(event):
39
39
  return True, "event is critical to the graph"
40
40
 
41
- # exclude certain URLs (e.g. javascript):
42
- # TODO: revisit this after httpx rework
43
- if event.type.startswith("URL") and self.name != "httpx" and "httpx-only" in event.tags:
44
- return False, (f"Omitting {event} from output because it's marked as httpx-only")
45
-
46
41
  # omit certain event types
47
42
  if event._omit:
48
43
  if "target" in event.tags:
@@ -0,0 +1,238 @@
1
+ import json
2
+ from enum import IntEnum
3
+ from bbot.modules.base import BaseModule
4
+
5
+
6
+ class RetireJSSeverity(IntEnum):
7
+ NONE = 0
8
+ LOW = 1
9
+ MEDIUM = 2
10
+ HIGH = 3
11
+ CRITICAL = 4
12
+
13
+ @classmethod
14
+ def from_string(cls, severity_str):
15
+ try:
16
+ return cls[severity_str.upper()]
17
+ except (KeyError, AttributeError):
18
+ return cls.NONE
19
+
20
+
21
+ class retirejs(BaseModule):
22
+ watched_events = ["URL_UNVERIFIED"]
23
+ produced_events = ["FINDING"]
24
+ flags = ["active", "safe", "web-thorough"]
25
+ meta = {
26
+ "description": "Detect vulnerable/out-of-date JavaScript libraries",
27
+ "created_date": "2025-08-19",
28
+ "author": "@liquidsec",
29
+ }
30
+ options = {
31
+ "version": "5.3.0",
32
+ "node_version": "18.19.1",
33
+ "severity": "medium",
34
+ }
35
+ options_desc = {
36
+ "version": "retire.js version",
37
+ "node_version": "Node.js version to install locally",
38
+ "severity": "Minimum severity level to report (none, low, medium, high, critical)",
39
+ }
40
+
41
+ deps_ansible = [
42
+ # Download Node.js binary (Linux x64)
43
+ {
44
+ "name": "Download Node.js binary (Linux x64)",
45
+ "get_url": {
46
+ "url": "https://nodejs.org/dist/v#{BBOT_MODULES_RETIREJS_NODE_VERSION}/node-v#{BBOT_MODULES_RETIREJS_NODE_VERSION}-linux-x64.tar.xz",
47
+ "dest": "#{BBOT_TEMP}/node-v#{BBOT_MODULES_RETIREJS_NODE_VERSION}-linux-x64.tar.xz",
48
+ "mode": "0644",
49
+ },
50
+ },
51
+ # Extract Node.js binary (x64)
52
+ {
53
+ "name": "Extract Node.js binary (x64)",
54
+ "unarchive": {
55
+ "src": "#{BBOT_TEMP}/node-v#{BBOT_MODULES_RETIREJS_NODE_VERSION}-linux-x64.tar.xz",
56
+ "dest": "#{BBOT_TOOLS}",
57
+ "remote_src": True,
58
+ },
59
+ },
60
+ # Remove existing node directory if it exists
61
+ {
62
+ "name": "Remove existing node directory",
63
+ "file": {"path": "#{BBOT_TOOLS}/node", "state": "absent"},
64
+ },
65
+ # Rename extracted directory to 'node' (x64)
66
+ {
67
+ "name": "Rename Node.js directory (x64)",
68
+ "command": "mv #{BBOT_TOOLS}/node-v#{BBOT_MODULES_RETIREJS_NODE_VERSION}-linux-x64 #{BBOT_TOOLS}/node",
69
+ },
70
+ # Make Node.js binary executable
71
+ {
72
+ "name": "Make Node.js binary executable",
73
+ "file": {"path": "#{BBOT_TOOLS}/node/bin/node", "mode": "0755"},
74
+ },
75
+ # Make npm executable
76
+ {
77
+ "name": "Make npm executable",
78
+ "file": {"path": "#{BBOT_TOOLS}/node/bin/npm", "mode": "0755"},
79
+ },
80
+ # Remove existing retirejs directory if it exists
81
+ {
82
+ "name": "Remove existing retirejs directory",
83
+ "file": {"path": "#{BBOT_TOOLS}/retirejs", "state": "absent"},
84
+ },
85
+ # Create retire.js local directory
86
+ {
87
+ "name": "Create retire.js directory in BBOT_TOOLS",
88
+ "file": {"path": "#{BBOT_TOOLS}/retirejs", "state": "directory", "mode": "0755"},
89
+ },
90
+ # Install retire.js locally using local Node.js
91
+ {
92
+ "name": "Install retire.js locally",
93
+ "shell": "cd #{BBOT_TOOLS}/retirejs && #{BBOT_TOOLS}/node/bin/node #{BBOT_TOOLS}/node/lib/node_modules/npm/bin/npm-cli.js install retire@#{BBOT_MODULES_RETIREJS_VERSION} --no-fund --no-audit --silent --no-optional",
94
+ "args": {"creates": "#{BBOT_TOOLS}/retirejs/node_modules/.bin/retire"},
95
+ "timeout": 600,
96
+ "ignore_errors": False,
97
+ },
98
+ # Fix retire script shebang to use our local node binary
99
+ {
100
+ "name": "Fix retire script shebang",
101
+ "shell": "sed -i '1s|#!/usr/bin/env node|#!#{BBOT_TOOLS}/node/bin/node|' #{BBOT_TOOLS}/retirejs/node_modules/.bin/retire",
102
+ },
103
+ # Make retire script executable
104
+ {
105
+ "name": "Make retire script executable",
106
+ "file": {"path": "#{BBOT_TOOLS}/retirejs/node_modules/.bin/retire", "mode": "0755"},
107
+ },
108
+ # Create retire cache directory
109
+ {
110
+ "name": "Create retire cache directory",
111
+ "file": {"path": "#{BBOT_CACHE}/retire_cache", "state": "directory", "mode": "0755"},
112
+ },
113
+ ]
114
+
115
+ accept_url_special = True
116
+ scope_distance_modifier = 1
117
+ _module_threads = 4
118
+
119
+ async def setup(self):
120
+ excavate_enabled = self.scan.config.get("excavate")
121
+ if not excavate_enabled:
122
+ return None, "retirejs will not function without excavate enabled"
123
+
124
+ # Validate severity level
125
+ valid_severities = ["none", "low", "medium", "high", "critical"]
126
+ configured_severity = self.config.get("severity", "medium").lower()
127
+ if configured_severity not in valid_severities:
128
+ return (
129
+ False,
130
+ f"Invalid severity level '{configured_severity}'. Valid options are: {', '.join(valid_severities)}",
131
+ )
132
+
133
+ self.repofile = await self.helpers.download(
134
+ "https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository-v4.json", cache_hrs=24
135
+ )
136
+ if not self.repofile:
137
+ return False, "failed to download retire.js repository file"
138
+ return True
139
+
140
+ async def handle_event(self, event):
141
+ js_file = await self.helpers.request(event.data)
142
+ if js_file:
143
+ js_file_body = js_file.text
144
+ if js_file_body:
145
+ js_file_body_saved = self.helpers.tempfile(js_file_body, pipe=False, extension="js")
146
+ results = await self.execute_retirejs(js_file_body_saved)
147
+ if not results:
148
+ self.warning("no output from retire.js")
149
+ return
150
+ results_json = json.loads(results)
151
+ if results_json.get("data"):
152
+ for file_result in results_json["data"]:
153
+ for component_result in file_result.get("results", []):
154
+ component = component_result.get("component", "unknown")
155
+ version = component_result.get("version", "unknown")
156
+ vulnerabilities = component_result.get("vulnerabilities", [])
157
+ for vuln in vulnerabilities:
158
+ severity = vuln.get("severity", "unknown")
159
+
160
+ # Filter by minimum severity level
161
+ min_severity = RetireJSSeverity.from_string(self.config.get("severity", "medium"))
162
+ vuln_severity = RetireJSSeverity.from_string(severity)
163
+ if vuln_severity < min_severity:
164
+ self.debug(
165
+ f"Skipping vulnerability with severity '{severity}' (below minimum '{min_severity.name.lower()}')"
166
+ )
167
+ continue
168
+
169
+ identifiers = vuln.get("identifiers", {})
170
+ summary = identifiers.get("summary", "Unknown vulnerability")
171
+ cves = identifiers.get("CVE", [])
172
+ description_parts = [
173
+ f"Vulnerable JavaScript library detected: {component} v{version}",
174
+ f"Severity: {severity.upper()}",
175
+ f"Summary: {summary}",
176
+ f"JavaScript URL: {event.data}",
177
+ ]
178
+ if cves:
179
+ description_parts.append(f"CVE(s): {', '.join(cves)}")
180
+
181
+ below_version = vuln.get("below", "")
182
+ at_or_above = vuln.get("atOrAbove", "")
183
+ if at_or_above and below_version:
184
+ description_parts.append(f"Affected versions: [{at_or_above} to {below_version})")
185
+ elif below_version:
186
+ description_parts.append(f"Affected versions: [< {below_version}]")
187
+ elif at_or_above:
188
+ description_parts.append(f"Affected versions: [>= {at_or_above}]")
189
+ description = " ".join(description_parts)
190
+ data = {
191
+ "description": description,
192
+ "severity": severity,
193
+ "component": component,
194
+ "url": event.parent.data["url"],
195
+ }
196
+ await self.emit_event(
197
+ data,
198
+ "FINDING",
199
+ parent=event,
200
+ context=f"{{module}} identified vulnerable JavaScript library {component} v{version} ({severity} severity)",
201
+ )
202
+
203
+ async def filter_event(self, event):
204
+ url_extension = getattr(event, "url_extension", "")
205
+ if url_extension != "js":
206
+ return False, f"it is a {url_extension} URL but retirejs only accepts js URLs"
207
+ return True
208
+
209
+ async def execute_retirejs(self, js_file):
210
+ cache_dir = self.helpers.cache_dir / "retire_cache"
211
+ retire_dir = self.scan.helpers.tools_dir / "retirejs"
212
+
213
+ # Use the retire CLI script directly with our local node binary
214
+ local_node_dir = self.scan.helpers.tools_dir / "node"
215
+ retire_cli_script = retire_dir / "node_modules" / "retire" / "lib" / "cli.js"
216
+
217
+ command = [
218
+ str(local_node_dir / "bin" / "node"),
219
+ str(retire_cli_script),
220
+ "--outputformat",
221
+ "json",
222
+ "--cachedir",
223
+ str(cache_dir),
224
+ "--path",
225
+ js_file,
226
+ "--jsrepo",
227
+ str(self.repofile),
228
+ ]
229
+
230
+ proxy = self.scan.web_config.get("http_proxy")
231
+ if proxy:
232
+ command.extend(["--proxy", proxy])
233
+
234
+ self.verbose(f"Running retire.js on {js_file}")
235
+ self.verbose(f"retire.js command: {command}")
236
+
237
+ result = await self.run_process(command)
238
+ return result.stdout
bbot/scanner/manager.py CHANGED
@@ -94,10 +94,6 @@ class ScanIngress(BaseInterceptModule):
94
94
  # special handling of URL extensions
95
95
  url_extension = getattr(event, "url_extension", None)
96
96
  if url_extension is not None:
97
- if url_extension in self.scan.url_extension_httpx_only:
98
- event.add_tag("httpx-only")
99
- event._omit = True
100
-
101
97
  # blacklist by extension
102
98
  if url_extension in self.scan.url_extension_blacklist:
103
99
  self.debug(
@@ -209,6 +205,13 @@ class ScanEgress(BaseInterceptModule):
209
205
  )
210
206
  event.internal = True
211
207
 
208
+ # mark special URLs (e.g. Javascript) as internal so they don't get output except when they're critical to the graph
209
+ if event.type.startswith("URL"):
210
+ extension = getattr(event, "url_extension", "")
211
+ if extension in self.scan.url_extension_special:
212
+ event.internal = True
213
+ self.debug(f"Making {event} internal because it is a special URL (extension {extension})")
214
+
212
215
  if event.type in self.scan.omitted_event_types:
213
216
  self.debug(f"Omitting {event} because its type is omitted in the config")
214
217
  event._omit = True
bbot/scanner/scanner.py CHANGED
@@ -230,8 +230,8 @@ class Scanner:
230
230
  )
231
231
 
232
232
  # url file extensions
233
+ self.url_extension_special = {e.lower() for e in self.config.get("url_extension_special", [])}
233
234
  self.url_extension_blacklist = {e.lower() for e in self.config.get("url_extension_blacklist", [])}
234
- self.url_extension_httpx_only = {e.lower() for e in self.config.get("url_extension_httpx_only", [])}
235
235
 
236
236
  # url querystring behavior
237
237
  self.url_querystring_remove = self.config.get("url_querystring_remove", True)
@@ -22,8 +22,8 @@ def test_bbot_multiprocess(bbot_httpserver):
22
22
  queue = multiprocessing.Queue()
23
23
  events_process = multiprocessing.Process(target=run_bbot_multiprocess, args=(queue,))
24
24
  events_process.start()
25
- events_process.join()
26
- events = queue.get()
25
+ events_process.join(timeout=300)
26
+ events = queue.get(timeout=10)
27
27
  assert len(events) >= 3
28
28
  scan_events = [e for e in events if e["type"] == "SCAN"]
29
29
  assert len(scan_events) == 2
@@ -209,7 +209,6 @@ async def test_events(events, helpers):
209
209
  javascript_event = scan.make_event("http://evilcorp.com/asdf/a.js?b=c#d", "URL_UNVERIFIED", parent=scan.root_event)
210
210
  assert "extension-js" in javascript_event.tags
211
211
  await scan.ingress_module.handle_event(javascript_event)
212
- assert "httpx-only" in javascript_event.tags
213
212
 
214
213
  # scope distance
215
214
  event1 = scan.make_event("1.2.3.4", dummy=True)
@@ -147,24 +147,18 @@ async def test_task_scan_handle_event_timeout(bbot_scanner):
147
147
 
148
148
  @pytest.mark.asyncio
149
149
  async def test_url_extension_handling(bbot_scanner):
150
- scan = bbot_scanner(config={"url_extension_blacklist": ["css"], "url_extension_httpx_only": ["js"]})
150
+ scan = bbot_scanner(config={"url_extension_blacklist": ["css"]})
151
151
  await scan._prep()
152
152
  assert scan.url_extension_blacklist == {"css"}
153
- assert scan.url_extension_httpx_only == {"js"}
154
153
  good_event = scan.make_event("https://evilcorp.com/a.txt", "URL", tags=["status-200"], parent=scan.root_event)
155
154
  bad_event = scan.make_event("https://evilcorp.com/a.css", "URL", tags=["status-200"], parent=scan.root_event)
156
- httpx_event = scan.make_event("https://evilcorp.com/a.js", "URL", tags=["status-200"], parent=scan.root_event)
157
155
  assert "blacklisted" not in bad_event.tags
158
- assert "httpx-only" not in httpx_event.tags
159
156
  result = await scan.ingress_module.handle_event(good_event)
160
157
  assert result is None
161
158
  result, reason = await scan.ingress_module.handle_event(bad_event)
162
159
  assert result is False
163
160
  assert reason == "event is blacklisted"
164
161
  assert "blacklisted" in bad_event.tags
165
- result = await scan.ingress_module.handle_event(httpx_event)
166
- assert result is None
167
- assert "httpx-only" in httpx_event.tags
168
162
 
169
163
  await scan._cleanup()
170
164
 
@@ -61,6 +61,7 @@ class ModuleTestBase:
61
61
  config=self.config,
62
62
  whitelist=module_test_base.whitelist,
63
63
  blacklist=module_test_base.blacklist,
64
+ force_start=getattr(module_test_base, "force_start", False),
64
65
  )
65
66
  self.events = []
66
67
  self.log = logging.getLogger(f"bbot.test.{module_test_base.name}")
@@ -24,14 +24,13 @@ class TestExcavate(ModuleTestBase):
24
24
  \\x3dwww6.test.notreal
25
25
  %0awww7.test.notreal
26
26
  \\u000awww8.test.notreal
27
- # these ones shouldn't get emitted because they're .js (url_extension_httpx_only)
28
- <a href="/a_relative.js">
29
- <link href="/link_relative.js">
30
- # these ones should
31
27
  <a href="/a_relative.txt">
32
28
  <link href="/link_relative.txt">
33
29
  <a href="mailto:bob@evilcorp.org?subject=help">Help</a>
34
30
  <li class="toctree-l3"><a class="reference internal" href="miscellaneous.html#x50-uart-driver">16x50 UART Driver</a></li>
31
+ # these ones should get emitted as URL_UNVERIFIED events (processed by httpx which has accept_js_url=True)
32
+ <a href="/a_relative.js">
33
+ <link href="/link_relative.js">
35
34
  """
36
35
  expect_args = {"method": "GET", "uri": "/"}
37
36
  respond_args = {"response_data": response_data}
@@ -63,8 +62,9 @@ class TestExcavate(ModuleTestBase):
63
62
  assert "www6.test.notreal" in event_data
64
63
  assert "www7.test.notreal" in event_data
65
64
  assert "www8.test.notreal" in event_data
66
- assert "http://127.0.0.1:8888/a_relative.js" not in event_data
67
- assert "http://127.0.0.1:8888/link_relative.js" not in event_data
65
+ # .js files should be emitted as URL_UNVERIFIED events (they are processed by httpx which has accept_js_url=True)
66
+ assert "http://127.0.0.1:8888/a_relative.js" in event_data
67
+ assert "http://127.0.0.1:8888/link_relative.js" in event_data
68
68
  assert "http://127.0.0.1:8888/a_relative.txt" in event_data
69
69
  assert "http://127.0.0.1:8888/link_relative.txt" in event_data
70
70
 
@@ -0,0 +1,159 @@
1
+ from .base import ModuleTestBase
2
+
3
+
4
+ class TestRetireJS(ModuleTestBase):
5
+ targets = ["http://127.0.0.1:8888"]
6
+ modules_overrides = ["httpx", "excavate", "retirejs"]
7
+
8
+ # HTML page with vulnerable JavaScript libraries
9
+ vulnerable_html = """<!doctype html>
10
+ <html lang="en">
11
+ <head>
12
+ <meta charset="utf-8" />
13
+ <title>retire.js test page</title>
14
+ </head>
15
+ <body>
16
+ <h1>retire.js test page</h1>
17
+ <p>This page includes JavaScript libraries for testing.</p>
18
+
19
+ <!-- jQuery 3.4.1 -->
20
+ <script src="/jquery-3.4.1.min.js"></script>
21
+
22
+ <!-- Lodash 4.17.11 -->
23
+ <script src="/lodash.min.js"></script>
24
+
25
+ <!-- Handlebars 4.0.5 -->
26
+ <script src="/handlebars.min.js"></script>
27
+
28
+ <script>
29
+ console.log('Libraries loaded');
30
+ </script>
31
+ </body>
32
+ </html>"""
33
+
34
+ # Sample jQuery 3.4.1 content
35
+ jquery_content = """/*!
36
+ * jQuery JavaScript Library v3.4.1
37
+ * https://jquery.com/
38
+ */
39
+ (function( global, factory ) {
40
+ "use strict";
41
+ factory( global );
42
+ })(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
43
+ var jQuery = function( selector, context ) {
44
+ return new jQuery.fn.init( selector, context );
45
+ };
46
+ jQuery.fn = jQuery.prototype = {};
47
+ jQuery.fn.jquery = "3.4.1";
48
+ if ( typeof noGlobal === "undefined" ) {
49
+ window.jQuery = window.$ = jQuery;
50
+ }
51
+ return jQuery;
52
+ });"""
53
+
54
+ # Sample Lodash 4.17.11 content
55
+ lodash_content = """/**
56
+ * @license
57
+ * Lodash lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
58
+ */
59
+ ;(function(){
60
+ var i="4.17.11";
61
+ var Mn={VERSION:i};
62
+ if(typeof define=="function"&&define.amd)define(function(){return Mn});else if(typeof module=="object"&&module.exports)module.exports=Mn;else this._=Mn}());"""
63
+
64
+ # Sample Handlebars 4.0.5 content
65
+ handlebars_content = """/*!
66
+ handlebars v4.0.5
67
+ */
68
+ !function(a,b){"object"==typeof exports&&"object"==typeof module?module.exports=b():"function"==typeof define&&define.amd?define([],b):"object"==typeof exports?exports.Handlebars=b():a.Handlebars=b()}(this,function(){
69
+ var Handlebars={};
70
+ Handlebars.VERSION="4.0.5";
71
+ return Handlebars;
72
+ });"""
73
+
74
+ async def setup_after_prep(self, module_test):
75
+ expect_args = {"uri": "/"}
76
+ respond_args = {"response_data": self.vulnerable_html}
77
+ module_test.set_expect_requests(expect_args, respond_args)
78
+
79
+ expect_args = {"uri": "/jquery-3.4.1.min.js"}
80
+ respond_args = {"response_data": self.jquery_content}
81
+ module_test.set_expect_requests(expect_args, respond_args)
82
+
83
+ expect_args = {"uri": "/lodash.min.js"}
84
+ respond_args = {"response_data": self.lodash_content}
85
+ module_test.set_expect_requests(expect_args, respond_args)
86
+
87
+ expect_args = {"uri": "/handlebars.min.js"}
88
+ respond_args = {"response_data": self.handlebars_content}
89
+ module_test.set_expect_requests(expect_args, respond_args)
90
+
91
+ def check(self, module_test, events):
92
+ # Check that excavate found the JavaScript URLs
93
+ url_unverified_events = [e for e in events if e.type == "URL_UNVERIFIED"]
94
+ js_url_events = [e for e in url_unverified_events if "extension-js" in e.tags]
95
+
96
+ # We should have found the JavaScript URLs
97
+ assert len(url_unverified_events) > 0, "No URL_UNVERIFIED events found - excavate may not be working"
98
+ assert len(js_url_events) >= 3, f"Expected at least 3 JavaScript URLs, found {len(js_url_events)}"
99
+
100
+ # Check for FINDING events generated by retirejs
101
+ finding_events = [e for e in events if e.type == "FINDING"]
102
+ retirejs_findings = [
103
+ e
104
+ for e in finding_events
105
+ if "vulnerable javascript library detected:" in e.data.get("description", "").lower()
106
+ ]
107
+
108
+ # We should have at least some findings from our vulnerable libraries
109
+ assert len(retirejs_findings) > 0, (
110
+ f"Expected retirejs to find vulnerabilities, but got {len(retirejs_findings)} findings"
111
+ )
112
+
113
+ # Check for specific expected vulnerability descriptions
114
+ descriptions = [finding.data.get("description", "") for finding in retirejs_findings]
115
+ all_descriptions = "\n".join(descriptions)
116
+
117
+ # Look for specific vulnerabilities we expect to find
118
+ expected_handlebars_vuln = "Vulnerable JavaScript library detected: handlebars v4.0.5 Severity: HIGH Summary: Regular Expression Denial of Service in Handlebars JavaScript URL: http://127.0.0.1:8888/handlebars.min.js CVE(s): CVE-2019-20922 Affected versions: [4.0.0 to 4.4.5)"
119
+ expected_jquery_vuln = "Vulnerable JavaScript library detected: jquery v3.4.1 Severity: MEDIUM Summary: Regex in its jQuery.htmlPrefilter sometimes may introduce XSS JavaScript URL: http://127.0.0.1:8888/jquery-3.4.1.min.js CVE(s): CVE-2020-11022 Affected versions: [1.2.0 to 3.5.0)"
120
+
121
+ # Verify at least one of the expected vulnerabilities is found
122
+ handlebars_found = expected_handlebars_vuln in all_descriptions
123
+ jquery_found = expected_jquery_vuln in all_descriptions
124
+
125
+ assert handlebars_found and jquery_found, (
126
+ f"Expected to find specific vulnerabilities but didn't find them. Found descriptions:\n{all_descriptions}"
127
+ )
128
+
129
+ # Basic validation of findings structure
130
+ for finding in retirejs_findings:
131
+ assert "description" in finding.data, "Finding should have description"
132
+ assert "url" in finding.data, "Finding should have url"
133
+ assert finding.parent.type == "URL_UNVERIFIED", "Parent should be URL_UNVERIFIED"
134
+
135
+
136
+ class TestRetireJSNoExcavate(ModuleTestBase):
137
+ targets = ["http://127.0.0.1:8888"]
138
+ modules_overrides = ["httpx", "retirejs"]
139
+ force_start = True # Allow scan to continue even if modules fail setup
140
+ config_overrides = {
141
+ "excavate": False,
142
+ }
143
+
144
+ def check(self, module_test, events):
145
+ # When excavate is disabled, retirejs should fail setup but scan should still run
146
+ retirejs_module = module_test.scan.modules.get("retirejs")
147
+
148
+ if retirejs_module:
149
+ # Check that the module exists but setup failed
150
+ setup_status = getattr(retirejs_module, "_setup_status", None)
151
+ if setup_status is not None:
152
+ success, error_msg = setup_status
153
+ assert success is False, "retirejs setup should have failed without excavate"
154
+ expected_error = "retirejs will not function without excavate enabled"
155
+ assert error_msg == expected_error, f"Expected error message '{expected_error}', but got '{error_msg}'"
156
+
157
+ # No retirejs findings should be generated since setup failed
158
+ retirejs_findings = [e for e in events if e.type == "FINDING" and getattr(e, "module", None) == "retirejs"]
159
+ assert len(retirejs_findings) == 0, "retirejs should not generate findings when setup fails"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bbot
3
- Version: 2.7.0.6962rc0
3
+ Version: 2.7.0.6989rc0
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=sl7Uz8uS9blFFoPuBAG5Q5s4a3n87_KdTeY83faWg3E,163
1
+ bbot/__init__.py,sha256=KqGrJ3EqVq7g_ze809iQbwFcd5RlmZeXtHWN9bjQaVY,163
2
2
  bbot/cli.py,sha256=1QJbANVw9Q3GFM92H2QRV2ds5756ulm08CDZwzwPpeI,11888
3
3
  bbot/core/__init__.py,sha256=l255GJE_DvUnWvrRb0J5lG-iMztJ8zVvoweDOfegGtI,46
4
4
  bbot/core/config/__init__.py,sha256=zYNw2Me6tsEr8hOOkLb4BQ97GB7Kis2k--G81S8vofU,342
@@ -25,7 +25,7 @@ bbot/core/helpers/dns/dns.py,sha256=erinIU5Ss2oBd0jgHucPwAgArBlQh2lQGeAZbxhq5lc,
25
25
  bbot/core/helpers/dns/engine.py,sha256=Xs2VyjvQFmjKciQOlEWO0ELUmXiUxwoj8YX3InVlOic,28777
26
26
  bbot/core/helpers/dns/helpers.py,sha256=aQroIuz5TxrCZ4zoplOaqLj3ZNgOgDRKn0xM8GKz2dA,8505
27
27
  bbot/core/helpers/dns/mock.py,sha256=FCPrihu6O4kun38IH70RfktsXIKKfe0Qx5PMzZVUdsY,2588
28
- bbot/core/helpers/files.py,sha256=9tVr3973QvX8l6o3TweD5_MCZiQpuJVffbzW0U7Z30U,5786
28
+ bbot/core/helpers/files.py,sha256=vWxx5AfH8khboawBdUi-KYvbjpybSMLGZpixylitGMQ,5811
29
29
  bbot/core/helpers/helper.py,sha256=u-q_Ka9pY1atvC-FChxYpURM7b3_0gaCNIHSG__Wi74,8538
30
30
  bbot/core/helpers/interactsh.py,sha256=VBYYH6-rWBofRsgemndK6iZNmyifOps8vgQOw2mac4k,12624
31
31
  bbot/core/helpers/libmagic.py,sha256=QMHyxjgDLb2jyjBvK1MQ-xt6WkGXhKcHu9ZP1li-sik,3460
@@ -50,7 +50,7 @@ bbot/core/modules.py,sha256=G4rRVF1bQzp62kwpgxwMa_FTV4-huWwtcd6HpW9jQf0,31970
50
50
  bbot/core/multiprocess.py,sha256=ocQHanskJ09gHwe7RZmwNdZyCOQyeyUoIHCtLbtvXUk,1771
51
51
  bbot/core/shared_deps.py,sha256=NeJmyakKxQQjN-H3rYGwGuHeVxDiVM_KnDfeVEeIbf4,9498
52
52
  bbot/db/sql/models.py,sha256=SrUdDOBCICzXJBY29p0VvILhMQ1JCuh725bqvIYogX0,4884
53
- bbot/defaults.yml,sha256=TTxtlnyE9vPihXjkGMDbBpNRlGa48GhRXS23iFsKUAg,7830
53
+ bbot/defaults.yml,sha256=-RAGZs-0wXTHKxCbU2i7XyX8AGZx2woN0_ID5P6GtFI,7961
54
54
  bbot/errors.py,sha256=xwQcD26nU9oc7-o0kv5jmEDTInmi8_W8eKAgQZZxdVM,953
55
55
  bbot/logger.py,sha256=wE-532v5FyKuSSoTdyW1xSfaOnLZB1axAJnB-uW2xrI,2745
56
56
  bbot/modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -64,7 +64,7 @@ bbot/modules/baddns.py,sha256=vSWWBiPfVowAg1yrBAx0rm8ViSh1O3VX7nI9Pn2Z5mo,6694
64
64
  bbot/modules/baddns_direct.py,sha256=G5WTKQ-jKJnSLijsOjyQKoR2Sx49fvACBvAC-b_yPck,3820
65
65
  bbot/modules/baddns_zone.py,sha256=8s2vIbU2MsLW6w12bDyw8FWBfdDRn2A2gWoMFEX4gPw,1036
66
66
  bbot/modules/badsecrets.py,sha256=2M515_nmDg24WTDqM01w-2DNN2H8BewvqnG_8hG6n3o,5110
67
- bbot/modules/base.py,sha256=EtFx7IUV-tBXlVt0UxwsmJRCaef20rp4yyWO6ko-KR0,78473
67
+ bbot/modules/base.py,sha256=uatsSs15fcaawbu7JTfQiY8WhkKQ-6WGGG41hIT2YeQ,78811
68
68
  bbot/modules/bevigil.py,sha256=0VLIxmeXRUI2-EoR6IzuHJMcX8KCHNNta-WYa3gVlDg,2862
69
69
  bbot/modules/bucket_amazon.py,sha256=mwjYeEAcdfOpjbOa1sD8U9KBMMVY_c8FoHjSGR9GQbg,730
70
70
  bbot/modules/bucket_azure.py,sha256=Jaa9XEL7w7VM0a-WAp05MOGdP5nt7hMpLzBsPq74_IM,1284
@@ -113,10 +113,10 @@ bbot/modules/github_workflows.py,sha256=xKntAFDeGuE4MqbEmhJyYXKbzoSh9tWYlHNlnF37
113
113
  bbot/modules/gitlab.py,sha256=9oWWpBijeHCjuFBfWW4HvNqt7bvJvrBgBjaaz_UPPnE,5964
114
114
  bbot/modules/google_playstore.py,sha256=N4QjzQag_bgDXfX17rytBiiWA-SQtYI2N0J_ZNEOdv0,3701
115
115
  bbot/modules/gowitness.py,sha256=hMhCz4O1sDJCzCzRIcmu0uNDgDDf9JzkFBwL1WuUum0,13144
116
- bbot/modules/graphql_introspection.py,sha256=-BAzNhBegup2sIYQdJ0jcafZFTGTZl3WoMygilyvfVA,4144
116
+ bbot/modules/graphql_introspection.py,sha256=xcrdW9lUJhxgIxJyZxfFQSk9vQxyBpvQmMoKWhRLdUA,4152
117
117
  bbot/modules/hackertarget.py,sha256=IsKs9PtxUHdLJKZydlRdW_loBE2KphQYi3lKDAd4odc,1029
118
118
  bbot/modules/host_header.py,sha256=uDjwidMdeNPMRfzQ2YW4REEGsZqnGOZHbOS6GgdNd9s,7686
119
- bbot/modules/httpx.py,sha256=z0sgnfLqIXyiadM0rKQK2p86lka7rC4pGCfTVUqU5Lk,8118
119
+ bbot/modules/httpx.py,sha256=tlQ6NKw8FJ6rGaNI1BnwKqjxZFn1MZeItGZgNab_Ydo,8177
120
120
  bbot/modules/hunt.py,sha256=zt-RKBiOlAKozHA-ZvuPeSOISEu7rIo2aHXQWEsILhw,6607
121
121
  bbot/modules/hunterio.py,sha256=dL8IUecJQzNJgvtHArQ1Lz574MbRTF7GbLxp6lLcs0o,2644
122
122
  bbot/modules/iis_shortnames.py,sha256=TD4kow8TB9slz0SENrfxmQ0Yo9WwsY6DB3j0vvgUIbA,16296
@@ -152,7 +152,7 @@ bbot/modules/oauth.py,sha256=s-Q6PYJl1OLncGgHzCV0QAzbkewT5zzKCRaa8GidBqc,6720
152
152
  bbot/modules/otx.py,sha256=GYi5GFLKlKuRHPYMqtq42bSulerkSpAWHM6ex5eK7ww,913
153
153
  bbot/modules/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
154
  bbot/modules/output/asset_inventory.py,sha256=nOIclasA3dGWfgzkgucQSivvXHQquEq312Y0Z6In49I,15479
155
- bbot/modules/output/base.py,sha256=HUkgtUNNfmSBVsVLr6XNfgXyBn9jWXBVm-ECJFWa3vQ,3820
155
+ bbot/modules/output/base.py,sha256=9qtuU3dqpyw5r9txGwLc3nuK5Cg9NDD3Ol80JKPxyKI,3530
156
156
  bbot/modules/output/csv.py,sha256=Nh8zcapgNAqbUKm-Jjb5kVL-INXwkn13oZ_Id-BEwUk,2865
157
157
  bbot/modules/output/discord.py,sha256=-6Dny6ZFG9W1OV54nqyamRZQk7TPzxw05nrSlb2Lwqw,730
158
158
  bbot/modules/output/emails.py,sha256=mzZideMCNfB8-naQANO5g8Y9HdgviAihRsdY_xPQjbQ,1095
@@ -187,6 +187,7 @@ bbot/modules/reflected_parameters.py,sha256=RjS-4C-XC9U-jC9J7AYNqwn6I-O2y3LvTRhB
187
187
  bbot/modules/report/affiliates.py,sha256=vvus8LylqOfP-lfGid0z4FS6MwOpNuRTcSJ9aSnybp4,1713
188
188
  bbot/modules/report/asn.py,sha256=D0jQkcZe_gEbmSokgSisYw6QolVJI9l71ksSMlOVTfo,9687
189
189
  bbot/modules/report/base.py,sha256=hOtZF41snTSlHZmzZndmOjfmtdKPy2-tfFBAxxbHcao,105
190
+ bbot/modules/retirejs.py,sha256=m56ESnaMg_xcsNgSCyPmMYFX3iXowh1B7IUxnr7nvpA,10423
190
191
  bbot/modules/robots.py,sha256=LGG6ixsxrlaCk-mi4Lp6kB2RB1v-25NhTAQxdQEtH8s,2172
191
192
  bbot/modules/securitytrails.py,sha256=5Jk_HTQP8FRq6A30sN19FU79uLJt7aiOsI2dxNkLDcM,1148
192
193
  bbot/modules/securitytxt.py,sha256=nwaTOnRAl2NWcEc3i_I9agB56QjqK8dHqiKRHPPkCPE,4558
@@ -248,14 +249,14 @@ bbot/presets/web-screenshots.yml,sha256=Kh5yDh2kKLJPxO5A67VxKWzou6XU1Ct-NFZqYsa6
248
249
  bbot/presets/web-thorough.yml,sha256=d7m8R64l9dcliuIhjVi0Q_PPAKk59Y6vkJSyLJe8LGI,115
249
250
  bbot/scanner/__init__.py,sha256=sJ7FoLQ1vwLscH8hju2PEUyGTZ_OwMVvW9b11CrCWdI,89
250
251
  bbot/scanner/dispatcher.py,sha256=_hsIegfUDrt8CUdXqgRvp1J0UwwzqVSDxjQmiviO41c,793
251
- bbot/scanner/manager.py,sha256=eyd_0IjnPH3e-tJSOwY-rxauVI6L9Ltr3pWmpPSO5Jc,11019
252
+ bbot/scanner/manager.py,sha256=HD83B5ZCUwZQZ5tDqCoQ7ZLq7XF2Y5hoqJt4xUwNx34,11304
252
253
  bbot/scanner/preset/__init__.py,sha256=If_YqKILIxjlaJvf8lFc5zQTHDkounLdC8x_72N-V10,49
253
254
  bbot/scanner/preset/args.py,sha256=Oto4sO8E9hKeQn6Fp8ua_WB3xvYI97GgnBFg5f4jh0Y,19547
254
255
  bbot/scanner/preset/conditions.py,sha256=hFL9cSIWGEsv2TfM5UGurf0c91cyaM8egb5IngBmIjA,1569
255
256
  bbot/scanner/preset/environ.py,sha256=9KbEOLWkUdoAf5Ez_2A1NNm6QduQElbnNnrPi6VDhZs,4731
256
257
  bbot/scanner/preset/path.py,sha256=X32-ZUmL7taIv37VKF1KfmeiK9fjuQOE7pWUTEbPK8c,2483
257
258
  bbot/scanner/preset/preset.py,sha256=G_aMMI33d2OlzNUwjfi5ddJdxa8nK0oF5HrYAsuregU,40708
258
- bbot/scanner/scanner.py,sha256=1b_M7OCeTUePi8Va9uvx-ZLD7L6-4fYCaxIcPMjNWC8,55584
259
+ bbot/scanner/scanner.py,sha256=Zz_syqeBpzc0Df1RH5HizylM2IPbFe7ZKd6e9quHWY4,55578
259
260
  bbot/scanner/stats.py,sha256=re93sArKXZSiD0Owgqk2J3Kdvfm3RL4Y9Qy_VOcaVk8,3623
260
261
  bbot/scanner/target.py,sha256=lI0Tn5prQiPiJE3WW-ZLx_l6EFqzAVabtyL-nfXJ8cE,10636
261
262
  bbot/scripts/docs.py,sha256=aYAHlcHtMAhM-XGTDiSpzccnX1dh0Xi_WxmC2bgylQ4,11373
@@ -270,7 +271,7 @@ bbot/test/test.conf,sha256=JX0-Wl7N7VN6x_hhkFL-RF4TDAHgL9OfNNdujfD7tHo,994
270
271
  bbot/test/test_output.ndjson,sha256=Jfor8nUJ3QTEwXxD6UULrFXM4zhP5wflWo_UNekM3V8,323
271
272
  bbot/test/test_step_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
272
273
  bbot/test/test_step_1/test__module__tests.py,sha256=SZGsvbq8mG7dIn93Ka8hnJsFt4QDXmrdvPavsU8NN40,1479
273
- bbot/test/test_step_1/test_bbot_fastapi.py,sha256=FNGvlax4lFZVd0T3HvV9SJh1lsngOX58GrUnJVzoy20,2531
274
+ bbot/test/test_step_1/test_bbot_fastapi.py,sha256=jujpDw4yedGpE2frPRMNV8mq4a5KuzW-_DGSkodxH_o,2552
274
275
  bbot/test/test_step_1/test_bloom_filter.py,sha256=Uy6qUZr4mSbD1VmU8Yq8u3ezqZziCjmZQiE844_FoX8,2143
275
276
  bbot/test/test_step_1/test_cli.py,sha256=yp61_di0vaEeC6USNCEOibc-Uh81fvEcqgfxLfNk09w,27586
276
277
  bbot/test/test_step_1/test_command.py,sha256=5IeGV6TKB0xtFEsfsU_0mNrOmEdIQiQ3FHkUmsBNoOI,6485
@@ -280,7 +281,7 @@ bbot/test/test_step_1/test_dns.py,sha256=6dKAhdQRZ_bceBrICIpaaV5MBGHeDVBQ-qSYD9B
280
281
  bbot/test/test_step_1/test_docs.py,sha256=YWVGNRfzcrvDmFekX0Cq9gutQplsqvhKTpZ0XK4tWvo,82
281
282
  bbot/test/test_step_1/test_engine.py,sha256=3HkCPtYhUxiZzfA-BRHpLsyaRj9wIXKbb49BCk9dILM,4267
282
283
  bbot/test/test_step_1/test_event_seeds.py,sha256=s_0BRqkahX4MYYqkmPqgcCsFrMbiXdTfLuKqNU2jkEU,6652
283
- bbot/test/test_step_1/test_events.py,sha256=Evm_rw5Y6W3H6eAGTlNcSWGALVo9PpKi_Rs80trPuXE,54312
284
+ bbot/test/test_step_1/test_events.py,sha256=FWSXAVFdVZaxxDS4anFKYTLm8AHVSULI9ZMHzKcaOLY,54263
284
285
  bbot/test/test_step_1/test_files.py,sha256=5Q_3jPpMXULxDHsanSDUaj8zF8bXzKdiJZHOmoYpLhQ,699
285
286
  bbot/test/test_step_1/test_helpers.py,sha256=7GP6-95yWRBGhx0-p6N7zZVEDcF9EO9wc0rkhs1JDsg,40281
286
287
  bbot/test/test_step_1/test_manager_deduplication.py,sha256=hZQpDXzg6zvzxFolVOcJuY-ME8NXjZUsqS70BRNXp8A,15594
@@ -289,14 +290,14 @@ bbot/test/test_step_1/test_modules_basic.py,sha256=ELpGlsthSq8HaxB5My8-ESVHqMxqd
289
290
  bbot/test/test_step_1/test_presets.py,sha256=HnJhKwDnVh9Y6adgxqe85677rWpnFil_WS5GjX21ZvM,40959
290
291
  bbot/test/test_step_1/test_python_api.py,sha256=Fk5bxEsPSjsMZ_CcRMTJft8I48EizwHJivG9Fy4jIu0,5502
291
292
  bbot/test/test_step_1/test_regexes.py,sha256=GEJE4NY6ge0WnG3BcFgRiT78ksy2xpFk6UdS9vGQMPs,15254
292
- bbot/test/test_step_1/test_scan.py,sha256=vnUF646MinLTdRAD_AwZ5sAqq6gmoHV7WlgNp5sjc_M,10875
293
+ bbot/test/test_step_1/test_scan.py,sha256=2tnIvh1PYDq1YoxT2MJZAMf_gg02v5aDaB6aknMjtmI,10490
293
294
  bbot/test/test_step_1/test_scope.py,sha256=S2nssENKJKCvgXUMyU8MFQmXHeUIz0C_sbWGkdYti2A,3063
294
295
  bbot/test/test_step_1/test_target.py,sha256=4Xz6Fns_6wa2O3AXDBvd7W04LCfZSCiit2lezQJicTI,19472
295
296
  bbot/test/test_step_1/test_web.py,sha256=qzMb5v_1l6fK6SvJZoHpBI3Zb7iaHU_VnenQ8UQIK-4,19637
296
297
  bbot/test/test_step_1/test_web_envelopes.py,sha256=28cwm_HZvdGo__uiaShO2AwTJ728FTKwpESRB418AIc,18259
297
298
  bbot/test/test_step_2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
298
299
  bbot/test/test_step_2/module_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
299
- bbot/test/test_step_2/module_tests/base.py,sha256=tLaO3Csb4DPv4Nuu5xjEPdYhsj70f_vZVV0voTisjyM,5942
300
+ bbot/test/test_step_2/module_tests/base.py,sha256=YBtOa38-NErIQAQ2W7b2a6Vd2ZBq2YHWFJpsNVJ5dwI,6019
300
301
  bbot/test/test_step_2/module_tests/test_module_affiliates.py,sha256=d6uAzb_MF4oNGFEBG7Y6T2y0unWpf1gqNxUXRaYqOdk,673
301
302
  bbot/test/test_step_2/module_tests/test_module_aggregate.py,sha256=hjxbMxAEFhS7W8RamBrM1t6T-tsLHq95MmQVfrYsock,487
302
303
  bbot/test/test_step_2/module_tests/test_module_ajaxpro.py,sha256=S2pFV0TgOJ01SMHnIxcoBkGZ8SAaQVY9o32DOFoZ1u4,3857
@@ -347,7 +348,7 @@ bbot/test/test_step_2/module_tests/test_module_dockerhub.py,sha256=9T8CFcFP32MOp
347
348
  bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py,sha256=Q7M3hrbEwOuORZXPS-pIGFTRzB2-g4cEvGtsEcTp7t8,8049
348
349
  bbot/test/test_step_2/module_tests/test_module_emailformat.py,sha256=cKxBPnEQ4AiRKV_-hSYEE6756ypst3hi6MN0L5RTukY,461
349
350
  bbot/test/test_step_2/module_tests/test_module_emails.py,sha256=bZjtO8N3GG2_g6SUEYprAFLcsi7SlwNPJJ0nODfrWYU,944
350
- bbot/test/test_step_2/module_tests/test_module_excavate.py,sha256=a-r8ZQwDVFlCCXQsM93j80FLY9jeb2N2HHY85Q3Q2aI,61475
351
+ bbot/test/test_step_2/module_tests/test_module_excavate.py,sha256=ywg-J2yl6LynHKIxEWmxBvV1RNFOZC2uCu1pGSbaoFo,61586
351
352
  bbot/test/test_step_2/module_tests/test_module_extractous.py,sha256=6wuZ978y5YIPYdR7av6otrY_5jUlzzuJDZ-DsBNOoLA,18197
352
353
  bbot/test/test_step_2/module_tests/test_module_ffuf.py,sha256=z8ihAM1WYss7QGXIjbi67cekg8iOemDjaM8YR9_qSEs,4100
353
354
  bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py,sha256=0-a9J-gq8bUtmxl_-QPVidwZ9KkCvgvoG30Ot3a8lqM,8406
@@ -403,6 +404,7 @@ bbot/test/test_step_2/module_tests/test_module_postman_download.py,sha256=u3lF7U
403
404
  bbot/test/test_step_2/module_tests/test_module_python.py,sha256=6UQVXGJ1ugfNbt9l_nN0q5FVxNWlpq6j0sZcB0Nh_Pg,184
404
405
  bbot/test/test_step_2/module_tests/test_module_rapiddns.py,sha256=zXHNLnUjLO22yRwrDFCZ40sRTmFVZEj9q_dyK8w1TYM,4441
405
406
  bbot/test/test_step_2/module_tests/test_module_reflected_parameters.py,sha256=4cY8yK9iImB1O68pi1lACcPEtNQ9-sud9Xl16fYB8cU,9003
407
+ bbot/test/test_step_2/module_tests/test_module_retirejs.py,sha256=1nzTxoMnq10N7X33soJ1hKNBvWXhAo5hdXo7HKaYRfw,6829
406
408
  bbot/test/test_step_2/module_tests/test_module_robots.py,sha256=8rRw4GpGE6tN_W3ohtpfWiji_bEEmD31wvxz7r1FqnI,1564
407
409
  bbot/test/test_step_2/module_tests/test_module_securitytrails.py,sha256=NB8_PhWN1-2s8wporRjI6rrQeQW4inoz4Z_mBhhycXo,758
408
410
  bbot/test/test_step_2/module_tests/test_module_securitytxt.py,sha256=ZGl1iZVVE_JfqC_AAYSLLdXGOu57rCM1rnCYlRNxrM0,2390
@@ -453,8 +455,8 @@ bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt,sha256=ZSIVebs7ptMvHx
453
455
  bbot/wordlists/top_open_ports_nmap.txt,sha256=LmdFYkfapSxn1pVuQC2LkOIY2hMLgG-Xts7DVtYzweM,42727
454
456
  bbot/wordlists/valid_url_schemes.txt,sha256=0B_VAr9Dv7aYhwi6JSBDU-3M76vNtzN0qEC_RNLo7HE,3310
455
457
  bbot/wordlists/wordninja_dns.txt.gz,sha256=DYHvvfW0TvzrVwyprqODAk4tGOxv5ezNmCPSdPuDUnQ,570241
456
- bbot-2.7.0.6962rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
457
- bbot-2.7.0.6962rc0.dist-info/METADATA,sha256=DTH-2tKHw4l3E3TgGl0LOvsdZGhRqrEb44Ct2HxSnag,18308
458
- bbot-2.7.0.6962rc0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
459
- bbot-2.7.0.6962rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
460
- bbot-2.7.0.6962rc0.dist-info/RECORD,,
458
+ bbot-2.7.0.6989rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
459
+ bbot-2.7.0.6989rc0.dist-info/METADATA,sha256=NO1Ezqw8WggKJwkDLTHpsQ3W5ZLHjZSFywDAl6XT9Vg,18308
460
+ bbot-2.7.0.6989rc0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
461
+ bbot-2.7.0.6989rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
462
+ bbot-2.7.0.6989rc0.dist-info/RECORD,,