bbot 2.3.2.5855rc0__py3-none-any.whl → 2.3.2.5889rc0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bbot might be problematic. Click here for more details.
- bbot/__init__.py +1 -1
- bbot/core/helpers/web/web.py +18 -1
- bbot/modules/deadly/ffuf.py +12 -6
- bbot/modules/ffuf_shortnames.py +69 -13
- bbot/modules/generic_ssrf.py +24 -11
- bbot/presets/web/dotnet-audit.yml +3 -0
- bbot/test/conftest.py +25 -20
- bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +1 -2
- bbot/test/test_step_2/module_tests/test_module_ffuf.py +24 -0
- bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +19 -0
- bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py +34 -3
- bbot/test/test_step_2/module_tests/test_module_host_header.py +1 -0
- {bbot-2.3.2.5855rc0.dist-info → bbot-2.3.2.5889rc0.dist-info}/METADATA +1 -1
- {bbot-2.3.2.5855rc0.dist-info → bbot-2.3.2.5889rc0.dist-info}/RECORD +17 -17
- {bbot-2.3.2.5855rc0.dist-info → bbot-2.3.2.5889rc0.dist-info}/LICENSE +0 -0
- {bbot-2.3.2.5855rc0.dist-info → bbot-2.3.2.5889rc0.dist-info}/WHEEL +0 -0
- {bbot-2.3.2.5855rc0.dist-info → bbot-2.3.2.5889rc0.dist-info}/entry_points.txt +0 -0
bbot/__init__.py
CHANGED
bbot/core/helpers/web/web.py
CHANGED
|
@@ -232,7 +232,7 @@ class WebHelper(EngineClient):
|
|
|
232
232
|
if success:
|
|
233
233
|
return filename
|
|
234
234
|
|
|
235
|
-
async def wordlist(self, path, lines=None, **kwargs):
|
|
235
|
+
async def wordlist(self, path, lines=None, zip=False, zip_filename=None, **kwargs):
|
|
236
236
|
"""
|
|
237
237
|
Asynchronous function for retrieving wordlists, either from a local path or a URL.
|
|
238
238
|
Allows for optional line-based truncation and caching. Returns the full path of the wordlist
|
|
@@ -242,6 +242,9 @@ class WebHelper(EngineClient):
|
|
|
242
242
|
path (str): The local or remote path of the wordlist.
|
|
243
243
|
lines (int, optional): Number of lines to read from the wordlist.
|
|
244
244
|
If specified, will return a truncated wordlist with this many lines.
|
|
245
|
+
zip (bool, optional): Whether to unzip the file after downloading. Defaults to False.
|
|
246
|
+
zip_filename (str, optional): The name of the file to extract from the ZIP archive.
|
|
247
|
+
Required if zip is True.
|
|
245
248
|
cache_hrs (float, optional): Number of hours to cache the downloaded wordlist.
|
|
246
249
|
Defaults to 720 hours (30 days) for remote wordlists.
|
|
247
250
|
**kwargs: Additional keyword arguments to pass to the 'download' function for remote wordlists.
|
|
@@ -259,6 +262,8 @@ class WebHelper(EngineClient):
|
|
|
259
262
|
Fetching and truncating to the first 100 lines
|
|
260
263
|
>>> wordlist_path = await self.helpers.wordlist("/root/rockyou.txt", lines=100)
|
|
261
264
|
"""
|
|
265
|
+
import zipfile
|
|
266
|
+
|
|
262
267
|
if not path:
|
|
263
268
|
raise WordlistError(f"Invalid wordlist: {path}")
|
|
264
269
|
if "cache_hrs" not in kwargs:
|
|
@@ -272,6 +277,18 @@ class WebHelper(EngineClient):
|
|
|
272
277
|
if not filename.is_file():
|
|
273
278
|
raise WordlistError(f"Unable to find wordlist at {path}")
|
|
274
279
|
|
|
280
|
+
if zip:
|
|
281
|
+
if not zip_filename:
|
|
282
|
+
raise WordlistError("zip_filename must be specified when zip is True")
|
|
283
|
+
try:
|
|
284
|
+
with zipfile.ZipFile(filename, "r") as zip_ref:
|
|
285
|
+
if zip_filename not in zip_ref.namelist():
|
|
286
|
+
raise WordlistError(f"File {zip_filename} not found in the zip archive {filename}")
|
|
287
|
+
zip_ref.extract(zip_filename, filename.parent)
|
|
288
|
+
filename = filename.parent / zip_filename
|
|
289
|
+
except Exception as e:
|
|
290
|
+
raise WordlistError(f"Error unzipping file {filename}: {e}")
|
|
291
|
+
|
|
275
292
|
if lines is None:
|
|
276
293
|
return filename
|
|
277
294
|
else:
|
bbot/modules/deadly/ffuf.py
CHANGED
|
@@ -17,6 +17,7 @@ class ffuf(BaseModule):
|
|
|
17
17
|
"lines": 5000,
|
|
18
18
|
"max_depth": 0,
|
|
19
19
|
"extensions": "",
|
|
20
|
+
"ignore_case": False,
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
options_desc = {
|
|
@@ -24,6 +25,7 @@ class ffuf(BaseModule):
|
|
|
24
25
|
"lines": "take only the first N lines from the wordlist when finding directories",
|
|
25
26
|
"max_depth": "the maximum directory depth to attempt to solve",
|
|
26
27
|
"extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)",
|
|
28
|
+
"ignore_case": "Only put lowercase words into the wordlist",
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
deps_common = ["ffuf"]
|
|
@@ -301,11 +303,12 @@ class ffuf(BaseModule):
|
|
|
301
303
|
]
|
|
302
304
|
if len(pre_emit_temp_canary) == 0:
|
|
303
305
|
yield found_json
|
|
306
|
+
|
|
304
307
|
else:
|
|
305
|
-
self.
|
|
306
|
-
"
|
|
308
|
+
self.verbose(
|
|
309
|
+
f"Would have reported URL [{found_json['url']}], but baseline check failed. This could be due to a WAF turning on mid-scan, or an unusual web server configuration."
|
|
307
310
|
)
|
|
308
|
-
self.
|
|
311
|
+
self.verbose(f"Aborting the current run against [{url}]")
|
|
309
312
|
return
|
|
310
313
|
|
|
311
314
|
yield found_json
|
|
@@ -328,7 +331,8 @@ class ffuf(BaseModule):
|
|
|
328
331
|
return self.helpers.tempfile(virtual_file, pipe=False), len(virtual_file)
|
|
329
332
|
|
|
330
333
|
def generate_wordlist(self, wordlist_file):
|
|
331
|
-
|
|
334
|
+
wordlist_set = set() # Use a set to avoid duplicates
|
|
335
|
+
ignore_case = self.config.get("ignore_case", False) # Get the ignore_case option
|
|
332
336
|
for line in self.helpers.read_file(wordlist_file):
|
|
333
337
|
line = line.strip()
|
|
334
338
|
if not line:
|
|
@@ -339,5 +343,7 @@ class ffuf(BaseModule):
|
|
|
339
343
|
if any(x in line for x in self.banned_characters):
|
|
340
344
|
self.debug(f"Skipping adding [{line}] to wordlist because it has a banned character")
|
|
341
345
|
continue
|
|
342
|
-
|
|
343
|
-
|
|
346
|
+
if ignore_case:
|
|
347
|
+
line = line.lower() # Convert to lowercase if ignore_case is enabled
|
|
348
|
+
wordlist_set.add(line) # Add to set to handle duplicates
|
|
349
|
+
return list(wordlist_set) # Convert set back to list before returning
|
bbot/modules/ffuf_shortnames.py
CHANGED
|
@@ -9,7 +9,6 @@ from bbot.modules.deadly.ffuf import ffuf
|
|
|
9
9
|
class ffuf_shortnames(ffuf):
|
|
10
10
|
watched_events = ["URL_HINT"]
|
|
11
11
|
produced_events = ["URL_UNVERIFIED"]
|
|
12
|
-
deps_pip = ["numpy"]
|
|
13
12
|
flags = ["aggressive", "active", "iis-shortnames", "web-thorough"]
|
|
14
13
|
meta = {
|
|
15
14
|
"description": "Use ffuf in combination IIS shortnames",
|
|
@@ -18,7 +17,6 @@ class ffuf_shortnames(ffuf):
|
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
options = {
|
|
21
|
-
"wordlist": "", # default is defined within setup function
|
|
22
20
|
"wordlist_extensions": "", # default is defined within setup function
|
|
23
21
|
"max_depth": 1,
|
|
24
22
|
"version": "2.0.0",
|
|
@@ -26,11 +24,11 @@ class ffuf_shortnames(ffuf):
|
|
|
26
24
|
"ignore_redirects": True,
|
|
27
25
|
"find_common_prefixes": False,
|
|
28
26
|
"find_delimiters": True,
|
|
27
|
+
"find_subwords": False,
|
|
29
28
|
"max_predictions": 250,
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
options_desc = {
|
|
33
|
-
"wordlist": "Specify wordlist to use when finding directories",
|
|
34
32
|
"wordlist_extensions": "Specify wordlist to use when making extension lists",
|
|
35
33
|
"max_depth": "the maximum directory depth to attempt to solve",
|
|
36
34
|
"version": "ffuf version",
|
|
@@ -38,21 +36,26 @@ class ffuf_shortnames(ffuf):
|
|
|
38
36
|
"ignore_redirects": "Explicitly ignore redirects (301,302)",
|
|
39
37
|
"find_common_prefixes": "Attempt to automatically detect common prefixes and make additional ffuf runs against them",
|
|
40
38
|
"find_delimiters": "Attempt to detect common delimiters and make additional ffuf runs against them",
|
|
39
|
+
"find_subwords": "Attempt to detect subwords and make additional ffuf runs against them",
|
|
41
40
|
"max_predictions": "The maximum number of predictions to generate per shortname prefix",
|
|
42
41
|
}
|
|
43
42
|
|
|
43
|
+
deps_pip = ["numpy"]
|
|
44
44
|
deps_common = ["ffuf"]
|
|
45
|
-
|
|
46
45
|
in_scope_only = True
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
virtual_file = []
|
|
47
|
+
supplementary_words = ["html", "ajax", "xml", "json", "api"]
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
def generate_templist(self, hint, shortname_type):
|
|
50
|
+
virtual_file = set() # Use a set to avoid duplicates
|
|
51
|
+
|
|
52
|
+
for prediction, score in self.predict(hint, self.max_predictions, model=shortname_type):
|
|
53
|
+
prediction_lower = prediction.lower() # Convert to lowercase
|
|
54
|
+
self.debug(f"Got prediction: [{prediction_lower}] from prefix [{hint}] with score [{score}]")
|
|
55
|
+
virtual_file.add(prediction_lower) # Add to set to ensure uniqueness
|
|
56
|
+
|
|
57
|
+
virtual_file.add(self.canary.lower()) # Ensure canary is also lowercase
|
|
58
|
+
return self.helpers.tempfile(list(virtual_file), pipe=False), len(virtual_file)
|
|
56
59
|
|
|
57
60
|
def predict(self, prefix, n=25, model="endpoint"):
|
|
58
61
|
predictor_name = f"{model}_predictor"
|
|
@@ -92,6 +95,7 @@ class ffuf_shortnames(ffuf):
|
|
|
92
95
|
self.wordlist_extensions = await self.helpers.wordlist(wordlist_extensions)
|
|
93
96
|
self.ignore_redirects = self.config.get("ignore_redirects")
|
|
94
97
|
self.max_predictions = self.config.get("max_predictions")
|
|
98
|
+
self.find_subwords = self.config.get("find_subwords")
|
|
95
99
|
|
|
96
100
|
class MinimalWordPredictor:
|
|
97
101
|
def __init__(self):
|
|
@@ -116,10 +120,11 @@ class ffuf_shortnames(ffuf):
|
|
|
116
120
|
return MinimalWordPredictor
|
|
117
121
|
return super().find_class(module, name)
|
|
118
122
|
|
|
119
|
-
|
|
123
|
+
self.info("Loading ffuf_shortnames prediction models, could take a while if not cached")
|
|
124
|
+
endpoint_model = await self.helpers.wordlist(
|
|
120
125
|
"https://raw.githubusercontent.com/blacklanternsecurity/wordpredictor/refs/heads/main/trained_models/endpoints.bin"
|
|
121
126
|
)
|
|
122
|
-
directory_model = await self.helpers.
|
|
127
|
+
directory_model = await self.helpers.wordlist(
|
|
123
128
|
"https://raw.githubusercontent.com/blacklanternsecurity/wordpredictor/refs/heads/main/trained_models/directories.bin"
|
|
124
129
|
)
|
|
125
130
|
|
|
@@ -133,8 +138,24 @@ class ffuf_shortnames(ffuf):
|
|
|
133
138
|
unpickler = CustomUnpickler(f)
|
|
134
139
|
self.directory_predictor = unpickler.load()
|
|
135
140
|
|
|
141
|
+
self.subword_list = []
|
|
142
|
+
if self.find_subwords:
|
|
143
|
+
self.debug("Acquiring ffuf_shortnames subword list")
|
|
144
|
+
subwords = await self.helpers.wordlist(
|
|
145
|
+
"https://raw.githubusercontent.com/nltk/nltk_data/refs/heads/gh-pages/packages/corpora/words.zip",
|
|
146
|
+
zip=True,
|
|
147
|
+
zip_filename="words/en",
|
|
148
|
+
)
|
|
149
|
+
with open(subwords, "r") as f:
|
|
150
|
+
subword_list_content = f.readlines()
|
|
151
|
+
self.subword_list = {word.lower().strip() for word in subword_list_content if 3 <= len(word.strip()) <= 5}
|
|
152
|
+
self.debug(f"Created subword_list with {len(self.subword_list)} words")
|
|
153
|
+
self.subword_list = self.subword_list.union(self.supplementary_words)
|
|
154
|
+
self.debug(f"Extended subword_list with supplementary words, total size: {len(self.subword_list)}")
|
|
155
|
+
|
|
136
156
|
self.per_host_collection = {}
|
|
137
157
|
self.shortname_to_event = {}
|
|
158
|
+
|
|
138
159
|
return True
|
|
139
160
|
|
|
140
161
|
def build_extension_list(self, event):
|
|
@@ -159,10 +180,20 @@ class ffuf_shortnames(ffuf):
|
|
|
159
180
|
return None
|
|
160
181
|
|
|
161
182
|
async def filter_event(self, event):
|
|
183
|
+
if "iis-magic-url" in event.tags:
|
|
184
|
+
return False, "iis-magic-url URL_HINTs are not solvable by ffuf_shortnames"
|
|
162
185
|
if event.parent.type != "URL":
|
|
163
186
|
return False, "its parent event is not of type URL"
|
|
164
187
|
return True
|
|
165
188
|
|
|
189
|
+
def find_subword(self, word):
|
|
190
|
+
for i in range(len(word), 2, -1): # Start from full length down to 3 characters
|
|
191
|
+
candidate = word[:i]
|
|
192
|
+
if candidate in self.subword_list:
|
|
193
|
+
leftover = word[i:]
|
|
194
|
+
return candidate, leftover
|
|
195
|
+
return None, word # No match found, return None and the original word
|
|
196
|
+
|
|
166
197
|
async def handle_event(self, event):
|
|
167
198
|
filename_hint = re.sub(r"~\d", "", event.parsed_url.path.rsplit(".", 1)[0].split("/")[-1]).lower()
|
|
168
199
|
|
|
@@ -256,6 +287,31 @@ class ffuf_shortnames(ffuf):
|
|
|
256
287
|
context=f'{{module}} brute-forced {ext.upper()} files with detected prefix "{ffuf_prefix}" and found {{event.type}}: {{event.data}}',
|
|
257
288
|
)
|
|
258
289
|
|
|
290
|
+
if self.config.get("find_subwords"):
|
|
291
|
+
subword, suffix = self.find_subword(filename_hint)
|
|
292
|
+
if subword:
|
|
293
|
+
if "shortname-directory" in event.tags:
|
|
294
|
+
tempfile, tempfile_len = self.generate_templist(suffix, "directory")
|
|
295
|
+
async for r in self.execute_ffuf(tempfile, root_url, prefix=subword, exts=["/"]):
|
|
296
|
+
await self.emit_event(
|
|
297
|
+
r["url"],
|
|
298
|
+
"URL_UNVERIFIED",
|
|
299
|
+
parent=event,
|
|
300
|
+
tags=[f"status-{r['status']}"],
|
|
301
|
+
context=f'{{module}} brute-forced directories with detected subword "{subword}" and found {{event.type}}: {{event.data}}',
|
|
302
|
+
)
|
|
303
|
+
elif "shortname-endpoint" in event.tags:
|
|
304
|
+
for ext in used_extensions:
|
|
305
|
+
tempfile, tempfile_len = self.generate_templist(suffix, "endpoint")
|
|
306
|
+
async for r in self.execute_ffuf(tempfile, root_url, prefix=subword, suffix=f".{ext}"):
|
|
307
|
+
await self.emit_event(
|
|
308
|
+
r["url"],
|
|
309
|
+
"URL_UNVERIFIED",
|
|
310
|
+
parent=event,
|
|
311
|
+
tags=[f"status-{r['status']}"],
|
|
312
|
+
context=f'{{module}} brute-forced {ext.upper()} files with detected subword "{subword}" and found {{event.type}}: {{event.data}}',
|
|
313
|
+
)
|
|
314
|
+
|
|
259
315
|
async def finish(self):
|
|
260
316
|
if self.config.get("find_common_prefixes"):
|
|
261
317
|
per_host_collection = dict(self.per_host_collection)
|
bbot/modules/generic_ssrf.py
CHANGED
|
@@ -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.
|
|
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" [{
|
|
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
|
-
|
|
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(
|
|
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)
|
|
@@ -17,6 +17,9 @@ config:
|
|
|
17
17
|
modules:
|
|
18
18
|
ffuf:
|
|
19
19
|
extensions: asp,aspx,ashx,asmx,ascx
|
|
20
|
+
extensions_ignore_case: True
|
|
21
|
+
ffuf_shortnames:
|
|
22
|
+
find_subwords: True
|
|
20
23
|
telerik:
|
|
21
24
|
exploit_RAU_crypto: True
|
|
22
25
|
include_subdirs: True # Run against every directory, not the default first received URL per-host
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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(
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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"
|
|
@@ -45,6 +45,30 @@ class TestFFUF2(TestFFUF):
|
|
|
45
45
|
assert not any(e.type == "URL_UNVERIFIED" and "11111111" in e.data for e in events)
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
class TestFFUF_ignorecase(TestFFUF):
|
|
49
|
+
test_wordlist = ["11111111", "Admin", "admin", "zzzjunkword2"]
|
|
50
|
+
config_overrides = {
|
|
51
|
+
"modules": {"ffuf": {"wordlist": tempwordlist(test_wordlist), "extensions": "php", "ignore_case": True}}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async def setup_before_prep(self, module_test):
|
|
55
|
+
expect_args = {"method": "GET", "uri": "/admin"}
|
|
56
|
+
respond_args = {"response_data": "alive admin page"}
|
|
57
|
+
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
58
|
+
|
|
59
|
+
expect_args = {"method": "GET", "uri": "/Admin"}
|
|
60
|
+
respond_args = {"response_data": "alive admin page"}
|
|
61
|
+
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
62
|
+
|
|
63
|
+
expect_args = {"method": "GET", "uri": "/"}
|
|
64
|
+
respond_args = {"response_data": "alive"}
|
|
65
|
+
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
66
|
+
|
|
67
|
+
def check(self, module_test, events):
|
|
68
|
+
assert any(e.type == "URL_UNVERIFIED" and "admin" in e.data for e in events)
|
|
69
|
+
assert not any(e.type == "URL_UNVERIFIED" and "Admin" in e.data for e in events)
|
|
70
|
+
|
|
71
|
+
|
|
48
72
|
class TestFFUFHeaders(TestFFUF):
|
|
49
73
|
test_wordlist = ["11111111", "console", "junkword1", "zzzjunkword2"]
|
|
50
74
|
config_overrides = {
|
|
@@ -8,6 +8,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
8
8
|
"modules": {
|
|
9
9
|
"ffuf_shortnames": {
|
|
10
10
|
"find_common_prefixes": True,
|
|
11
|
+
"find_subwords": True,
|
|
11
12
|
"wordlist": tempwordlist(test_wordlist),
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -142,6 +143,16 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
142
143
|
tags=["shortname-endpoint"],
|
|
143
144
|
)
|
|
144
145
|
)
|
|
146
|
+
|
|
147
|
+
seed_events.append(
|
|
148
|
+
module_test.scan.make_event(
|
|
149
|
+
"http://127.0.0.1:8888/newpro~1.asp",
|
|
150
|
+
"URL_HINT",
|
|
151
|
+
parent_event,
|
|
152
|
+
module="iis_shortnames",
|
|
153
|
+
tags=["shortname-endpoint"],
|
|
154
|
+
)
|
|
155
|
+
)
|
|
145
156
|
module_test.scan.target.seeds.events = set(seed_events)
|
|
146
157
|
|
|
147
158
|
expect_args = {"method": "GET", "uri": "/administrator.aspx"}
|
|
@@ -172,6 +183,10 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
172
183
|
respond_args = {"response_data": "alive"}
|
|
173
184
|
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
174
185
|
|
|
186
|
+
expect_args = {"method": "GET", "uri": "/newproxy.aspx"}
|
|
187
|
+
respond_args = {"response_data": "alive"}
|
|
188
|
+
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
|
|
189
|
+
|
|
175
190
|
def check(self, module_test, events):
|
|
176
191
|
basic_detection = False
|
|
177
192
|
directory_detection = False
|
|
@@ -180,6 +195,7 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
180
195
|
directory_delimiter_detection = False
|
|
181
196
|
prefix_delimiter_detection = False
|
|
182
197
|
short_extensions_detection = False
|
|
198
|
+
subword_detection = False
|
|
183
199
|
|
|
184
200
|
for e in events:
|
|
185
201
|
if e.type == "URL_UNVERIFIED":
|
|
@@ -197,6 +213,8 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
197
213
|
prefix_delimiter_detection = True
|
|
198
214
|
if e.data == "http://127.0.0.1:8888/short.pl":
|
|
199
215
|
short_extensions_detection = True
|
|
216
|
+
if e.data == "http://127.0.0.1:8888/newproxy.aspx":
|
|
217
|
+
subword_detection = True
|
|
200
218
|
|
|
201
219
|
assert basic_detection
|
|
202
220
|
assert directory_detection
|
|
@@ -205,3 +223,4 @@ class TestFFUFShortnames(ModuleTestBase):
|
|
|
205
223
|
assert directory_delimiter_detection
|
|
206
224
|
assert prefix_delimiter_detection
|
|
207
225
|
assert short_extensions_detection
|
|
226
|
+
assert subword_detection
|
|
@@ -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
|
-
|
|
27
|
-
|
|
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,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: bbot
|
|
3
|
-
Version: 2.3.2.
|
|
3
|
+
Version: 2.3.2.5889rc0
|
|
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=
|
|
1
|
+
bbot/__init__.py,sha256=s95CAchRkg61vjHu7w4wiXXBH-BYyVsWnZryET4F-Ng,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
|
|
@@ -42,7 +42,7 @@ bbot/core/helpers/web/__init__.py,sha256=pIEkL3DhjaGTSmZ7D3yKKYwWpntoLRILekV2wWs
|
|
|
42
42
|
bbot/core/helpers/web/client.py,sha256=UTjNnsAz-bPO6GEc1lEm_ZhatwaVOIGG7nRIn7KdZAQ,3562
|
|
43
43
|
bbot/core/helpers/web/engine.py,sha256=mzXpYmlB1pvNSXs8FuliGMv7myUwAcQWTtnMHqblMHA,8875
|
|
44
44
|
bbot/core/helpers/web/ssl_context.py,sha256=aWVgl-d0HoE8B4EBKNxaa5UAzQmx79DjDByfBw9tezo,356
|
|
45
|
-
bbot/core/helpers/web/web.py,sha256=
|
|
45
|
+
bbot/core/helpers/web/web.py,sha256=sesBGwqXRmePwQIScfg8PbrlCPMArQVj55E1aJsWctI,23685
|
|
46
46
|
bbot/core/helpers/wordcloud.py,sha256=QM8Z1N01_hXrRFKQjvRL-IzOOC7ZMKjuSBID3u77Sxg,19809
|
|
47
47
|
bbot/core/modules.py,sha256=U0Z2UoZAOPG9lLvR9Juc3UwdWCc_xbktF4t_NoiKPrY,31385
|
|
48
48
|
bbot/core/multiprocess.py,sha256=ocQHanskJ09gHwe7RZmwNdZyCOQyeyUoIHCtLbtvXUk,1771
|
|
@@ -81,7 +81,7 @@ bbot/modules/code_repository.py,sha256=x70Z45VnNNMF8BPkHfGWZXsZXw_fStGB3y0-8jbP1
|
|
|
81
81
|
bbot/modules/credshed.py,sha256=HAF5wgRGKIIpdMAe4mIAtkZRLmFYjMFyXtjjst6RJ20,4203
|
|
82
82
|
bbot/modules/crt.py,sha256=6Zm90VKXwYYN6Sab0gwwhTARrtnQIqALJTVtFWMMTGk,1369
|
|
83
83
|
bbot/modules/deadly/dastardly.py,sha256=dxPkJUfAsuddDDuI_uVyTUxkJ5eps92nSrPtpBOTlQg,5315
|
|
84
|
-
bbot/modules/deadly/ffuf.py,sha256=
|
|
84
|
+
bbot/modules/deadly/ffuf.py,sha256=sCledEgIi1ZgAhb-XlwbLIH3wBD5dSELZAEun_pNLOk,14745
|
|
85
85
|
bbot/modules/deadly/nuclei.py,sha256=hUoqdN_o3f1DQ30I6ltlW63NHT6OGhivoWi8gNlLMuQ,17808
|
|
86
86
|
bbot/modules/deadly/vhost.py,sha256=m7RdR0w7Hs38IGVHUu_3Er-_5ABVdalRG_8znQepxD0,5456
|
|
87
87
|
bbot/modules/dehashed.py,sha256=iyzWHmJs6zC7FsRhw9_AdkckQKCf_0oNnL9RwG409r0,5071
|
|
@@ -98,11 +98,11 @@ bbot/modules/dockerhub.py,sha256=JQkujjqvQRzQuvHjQ7JbFs_VlJj8dLRPRObAkBgUQhc,349
|
|
|
98
98
|
bbot/modules/dotnetnuke.py,sha256=zipcHyNYr2FEecStb1Yrm938ps01RvHV8NnyqAvnGGc,10537
|
|
99
99
|
bbot/modules/emailformat.py,sha256=RLPJW-xitYB-VT4Lp08qVzFkXx_kMyV_035JT_Yf4fM,1082
|
|
100
100
|
bbot/modules/extractous.py,sha256=VSGKmHPAA_4r62jaN8Yqi3JcjehjxpI2lhe8i2j786s,4648
|
|
101
|
-
bbot/modules/ffuf_shortnames.py,sha256=
|
|
101
|
+
bbot/modules/ffuf_shortnames.py,sha256=iJnm6bvFyQXfzOGnUioficE6v59QkaErY7mo4m6m7o0,18618
|
|
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=
|
|
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
|
|
@@ -218,7 +218,7 @@ bbot/presets/subdomain-enum.yml,sha256=tn9h8TlVB_uS3nKZFUP72HzceoRONSef66mGLWzxj
|
|
|
218
218
|
bbot/presets/tech-detect.yml,sha256=0eEzviy33kZojXpUfKVK0lHhiQrNAopCMEJNL8Clunw,176
|
|
219
219
|
bbot/presets/web/dirbust-heavy.yml,sha256=NDqu7p0Hx1RsZCVnaEWRgI_iL9O0io-tvWerxJf36SM,653
|
|
220
220
|
bbot/presets/web/dirbust-light.yml,sha256=5zSANdjKfYh49kFlsElYY2G6acVrZFzDCEkyqwU6oOQ,203
|
|
221
|
-
bbot/presets/web/dotnet-audit.yml,sha256=
|
|
221
|
+
bbot/presets/web/dotnet-audit.yml,sha256=FViiccDXG08P3INNe06bLPeatejbw8Kb1HW5xgdUJNU,520
|
|
222
222
|
bbot/presets/web/iis-shortnames.yml,sha256=EcYKMpl-cI8Xb79_u4wQS42yFXxDpLH9OqINcFUXoTE,176
|
|
223
223
|
bbot/presets/web/paramminer.yml,sha256=VuiXkxrOAeqXlk9Gmuo938_REvbbTH6-lxTrlyWAvZ4,163
|
|
224
224
|
bbot/presets/web-basic.yml,sha256=6YWSYclbuf9yr8-gILDpLvOUj5QjP4rlarm5_d5iBFw,79
|
|
@@ -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=
|
|
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,17 +320,17 @@ 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=
|
|
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
|
|
327
327
|
bbot/test/test_step_2/module_tests/test_module_extractous.py,sha256=PuTE5rkEIFPwU9lhCYpTgNSkrVjcXm8PClbfOkfRS84,17973
|
|
328
|
-
bbot/test/test_step_2/module_tests/test_module_ffuf.py,sha256=
|
|
329
|
-
bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py,sha256=
|
|
328
|
+
bbot/test/test_step_2/module_tests/test_module_ffuf.py,sha256=z8ihAM1WYss7QGXIjbi67cekg8iOemDjaM8YR9_qSEs,4100
|
|
329
|
+
bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py,sha256=aq8ycPMJmFJJO6mqM2EaFZoKBEpm6Umfz05OMMwxu4Q,8354
|
|
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=
|
|
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
|
|
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.
|
|
427
|
-
bbot-2.3.2.
|
|
428
|
-
bbot-2.3.2.
|
|
429
|
-
bbot-2.3.2.
|
|
430
|
-
bbot-2.3.2.
|
|
426
|
+
bbot-2.3.2.5889rc0.dist-info/LICENSE,sha256=GzeCzK17hhQQDNow0_r0L8OfLpeTKQjFQwBQU7ZUymg,32473
|
|
427
|
+
bbot-2.3.2.5889rc0.dist-info/METADATA,sha256=ARrEoX3gXC9hWPDf2FWNjfpfZpR6Ta9BCdSudw0fvMg,18224
|
|
428
|
+
bbot-2.3.2.5889rc0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
429
|
+
bbot-2.3.2.5889rc0.dist-info/entry_points.txt,sha256=cWjvcU_lLrzzJgjcjF7yeGuRA_eDS8pQ-kmPUAyOBfo,38
|
|
430
|
+
bbot-2.3.2.5889rc0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|