Skip to content
Draft
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
172 commits
Select commit Hold shift + click to select a range
fefc52a
waf_bypass initial
liquidsec Aug 1, 2025
466a2ad
fixing source event bug
liquidsec Aug 4, 2025
7049bff
continued development
liquidsec Aug 6, 2025
2041483
Merge branch 'dev' into waf-bypass
liquidsec Aug 6, 2025
f68de32
adding asn helper test, fixing report
liquidsec Aug 6, 2025
b1e175a
normalizing nomenclature, adding tests
liquidsec Aug 7, 2025
3cd55a6
add meta
liquidsec Aug 11, 2025
c228095
Merge branch 'dev' into waf-bypass
liquidsec Aug 11, 2025
163ea09
output modifications
liquidsec Aug 15, 2025
dee9079
fix debug messages and add ip filter to ip check
liquidsec Aug 15, 2025
9626f28
add preset
liquidsec Aug 15, 2025
cae129d
fix bug when no subnets in asn
liquidsec Aug 18, 2025
53ea0b3
virtualhost overhaul initial
liquidsec Aug 27, 2025
3bf032a
tweak
liquidsec Aug 27, 2025
38d4d2e
virtualhost update major refactor
liquidsec Aug 30, 2025
454d7d1
virtual host another major refactor
liquidsec Sep 2, 2025
f04c486
changes to as_completed
liquidsec Sep 2, 2025
1d16b49
pinned curl
liquidsec Sep 2, 2025
7c32cb1
fix missing arg
liquidsec Sep 2, 2025
3447866
finish rename
liquidsec Sep 2, 2025
0d98531
small refactor
liquidsec Sep 2, 2025
eb93201
fix async handling
liquidsec Sep 3, 2025
84c0f8e
presets and other adjustments
liquidsec Sep 3, 2025
ef1674f
change as_completed to only accept coros
liquidsec Sep 3, 2025
bd51281
starting to back out of debug, more tweaks
liquidsec Sep 4, 2025
d160941
special virtual host only ignore strings
liquidsec Sep 4, 2025
d19f324
add module test
liquidsec Sep 4, 2025
a5847c5
Merge branch 'dev' into virtualhost-upgrade
liquidsec Sep 4, 2025
ba9fcae
typo
liquidsec Sep 4, 2025
951ca41
fix virtual_host event test fixtures
liquidsec Sep 4, 2025
9940355
lint
liquidsec Sep 4, 2025
525481e
yanking debug stuff, polishing
liquidsec Sep 4, 2025
b3757ec
make curl command message debug only
liquidsec Sep 4, 2025
3082880
Merge branch 'dev' into virtualhost-upgrade
liquidsec Sep 4, 2025
f160f00
finish() scan bug fix
liquidsec Sep 4, 2025
978b5cd
go mariners
liquidsec Sep 5, 2025
7def332
as_completed error handling, tests
liquidsec Sep 5, 2025
2ba8318
yet another major refactor
liquidsec Sep 5, 2025
824d35d
i let the clanker try to alphabetize
liquidsec Sep 5, 2025
9fdf579
lint
liquidsec Sep 5, 2025
53512df
fixing test
liquidsec Sep 6, 2025
fbeadc0
adjustments
liquidsec Sep 7, 2025
cbe372d
more refactoring
liquidsec Sep 8, 2025
716652e
error message adjustments
liquidsec Sep 8, 2025
bf978b9
error handling
liquidsec Sep 9, 2025
05505d8
add web.response_similarity web helper
liquidsec Sep 10, 2025
7a24d16
use new response_similarity helper
liquidsec Sep 10, 2025
7f4c445
Merge branch 'virtualhost-upgrade' into waf-bypass
liquidsec Sep 10, 2025
c926393
initial change from merge
liquidsec Sep 10, 2025
6d4c88b
further generalizing comparison helper
liquidsec Sep 10, 2025
f957f5e
Merge branch 'virtualhost-upgrade' into waf-bypass
liquidsec Sep 10, 2025
41aa18c
real asn db url
liquidsec Sep 11, 2025
b147ae5
rework comparison logic to use helper
liquidsec Sep 11, 2025
2ed2296
correct ASN expansion, bug fixes, tests
liquidsec Sep 19, 2025
fafdad1
bugfix
liquidsec Sep 19, 2025
b6aa2a5
fixing tests
liquidsec Sep 19, 2025
bff0b7e
lint
liquidsec Sep 19, 2025
2aa0685
fixing bug
liquidsec Sep 20, 2025
5f01007
fix tests
liquidsec Sep 20, 2025
d5fbae3
fix more tests
liquidsec Sep 20, 2025
30624c6
fixing test
liquidsec Sep 20, 2025
ce16a80
more test fixes, adjustments to prep
liquidsec Sep 20, 2025
4f65a46
fixing slop
liquidsec Sep 22, 2025
d8a5a64
more reworking around the prep() change
liquidsec Sep 22, 2025
3507d00
more test fixing
liquidsec Sep 22, 2025
06b8de5
more test fixes
liquidsec Sep 22, 2025
32efd2e
rate-limit use retry-after
liquidsec Sep 22, 2025
0c43022
more test fixes
liquidsec Sep 22, 2025
ee844c6
use correct method
liquidsec Sep 22, 2025
1b12214
change to new function name
liquidsec Sep 22, 2025
6effa6b
fix asn helper access
liquidsec Sep 22, 2025
80789b0
yet more test fixes
liquidsec Sep 22, 2025
c0f9467
Merge branch 'dev' into virtualhost-upgrade
liquidsec Sep 22, 2025
7a2bc99
yet even still more test fixes
liquidsec Sep 22, 2025
d483997
slightly change waf_bypass detection criteria
liquidsec Sep 22, 2025
8915855
massive test fixes (from prep() changes)
liquidsec Sep 23, 2025
183a6f0
yet even more test fixes still
liquidsec Sep 23, 2025
2d5498e
ruff format
liquidsec Sep 23, 2025
9555205
Merge branch 'virtualhost-upgrade' into waf-bypass
liquidsec Sep 23, 2025
ee03e61
fix even yet more additional tests
liquidsec Sep 23, 2025
aab237a
ugggggggggggggggggggggggggggggg tests
liquidsec Sep 23, 2025
11710ea
test initialize order
liquidsec Sep 23, 2025
40a35c1
another test fix
liquidsec Sep 23, 2025
86b3f03
more test stuff again the sequel
liquidsec Sep 23, 2025
20ef830
even more :(
liquidsec Sep 24, 2025
391155f
test fix
liquidsec Sep 24, 2025
3dec03a
asdf
liquidsec Sep 24, 2025
d455b7c
better large ip_range behavior
liquidsec Sep 24, 2025
df66c25
fixing unknown asn system
liquidsec Sep 25, 2025
eb7f570
change to simhash for comparison
liquidsec Sep 26, 2025
33ef6db
remove debug messages
liquidsec Sep 26, 2025
9576232
debug junk
liquidsec Sep 26, 2025
323284e
add simhash helper
liquidsec Sep 26, 2025
d3a68d5
fixing inefficient seed event class sorting
liquidsec Sep 26, 2025
39bc9fe
remove unnecessary warning
liquidsec Sep 26, 2025
ddc0a9c
DRY
liquidsec Sep 26, 2025
3faf36f
refactor for correct api format
liquidsec Sep 26, 2025
bdce02d
LRU cache, fix rate limiting
liquidsec Sep 26, 2025
db741fb
Merge branch 'waf-bypass' into better-text-compare
liquidsec Sep 26, 2025
5a1a66d
remove debug
liquidsec Sep 26, 2025
a66b012
comments
TheTechromancer Sep 26, 2025
4da27b8
remove per host only
liquidsec Sep 26, 2025
12bf1f9
simhash helper update
liquidsec Sep 27, 2025
f446117
major waf_bypass refactor
liquidsec Sep 27, 2025
321c259
format
liquidsec Sep 27, 2025
6231157
Merge branch 'waf-bypass' into better-text-compare
liquidsec Sep 27, 2025
35bc4b7
Merge pull request #2713 from blacklanternsecurity/better-text-compare
liquidsec Sep 27, 2025
49e724b
Merge branch 'dev' into virtualhost-upgrade
liquidsec Sep 29, 2025
0173e2a
Merge branch 'virtualhost-upgrade' into waf-bypass
liquidsec Sep 29, 2025
cd0c3f9
Merge branch 'dev' into virtualhost-upgrade
liquidsec Oct 9, 2025
635aa4d
Merge branch 'virtualhost-upgrade' into waf-bypass
liquidsec Oct 9, 2025
0cc459d
add virtualhost http_response emittal
liquidsec Oct 15, 2025
ca64515
fix header extraction curl helper
liquidsec Oct 16, 2025
7bb3989
Merge pull request #2738 from blacklanternsecurity/virtualhost-httpre…
liquidsec Oct 16, 2025
15e5eb5
Merge branch 'dev' into virtualhost-upgrade
liquidsec Oct 16, 2025
cf9ae83
Merge branch 'virtualhost-upgrade' into waf-bypass
liquidsec Oct 16, 2025
02129b0
remove unnecessary cache
liquidsec Oct 16, 2025
5147d68
forklifting asn human output code
liquidsec Oct 16, 2025
2863934
clean up duplicate
liquidsec Oct 16, 2025
5cd05d0
more efficient asn report (using helper)
liquidsec Oct 16, 2025
1de5db2
some cleanup
liquidsec Oct 17, 2025
3e03865
Merge pull request #2553 from blacklanternsecurity/waf-bypass
liquidsec Oct 17, 2025
2191c72
temporarility removing new modules
liquidsec Oct 17, 2025
2686341
temporarily remove presets
liquidsec Oct 17, 2025
31c3e12
temp removal
liquidsec Oct 17, 2025
4da2319
Restore virtualhost and WAF bypass modules and tests
liquidsec Oct 17, 2025
5f49ae3
Restore virtualhost/WAF bypass modules and revert web helpers to pre-…
liquidsec Oct 17, 2025
56f5d53
ruff format
liquidsec Oct 17, 2025
1740a28
temporarily revert
liquidsec Oct 17, 2025
05f1cab
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Oct 17, 2025
a7ce13a
just fixing stuff
liquidsec Oct 17, 2025
e8e50e0
more merge stuff
liquidsec Oct 17, 2025
04206e2
fix test again
liquidsec Oct 17, 2025
a94ca10
oops
liquidsec Oct 17, 2025
96658b6
fixing test
liquidsec Oct 17, 2025
6ce1295
temp removal
liquidsec Oct 17, 2025
9f0ab3d
Restore virtualhost and WAF bypass modules and tests
liquidsec Oct 17, 2025
582f4de
rebase
liquidsec Oct 17, 2025
fb20516
just fixing stuff
liquidsec Oct 17, 2025
d634166
oops
liquidsec Oct 17, 2025
80fa122
Merge remote-tracking branch 'refs/remotes/origin/virtualhost-upgrade…
liquidsec Oct 17, 2025
6a1698f
fixing
liquidsec Oct 17, 2025
e7165e8
Merge branch 'dev' into asn-as-targets
liquidsec Nov 21, 2025
b5bcec8
Merge branch 'dev' into asn-as-targets
liquidsec Dec 3, 2025
7e7f76f
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Dec 3, 2025
e8f01da
fix test
liquidsec Dec 3, 2025
2954d4e
add pyopenssl dep
liquidsec Dec 3, 2025
d06a385
fixing next() bug
liquidsec Dec 4, 2025
7c4a91d
untangle cli arg issues
liquidsec Dec 5, 2025
2720cae
ensure a description exists
liquidsec Dec 5, 2025
6554bd9
more adjustments to scan initialization
liquidsec Dec 5, 2025
48f76ba
lint
liquidsec Dec 5, 2025
c2052a4
more early preset handling changes
liquidsec Dec 5, 2025
6b9af37
Merge branch 'dev' into asn-as-targets
liquidsec Dec 5, 2025
b749538
Merge pull request #2810 from blacklanternsecurity/untangle-cli-args
liquidsec Dec 5, 2025
61fc201
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Dec 5, 2025
703d9cb
fixing dev sync merge
liquidsec Jan 19, 2026
e8a8bc4
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Jan 19, 2026
e974572
Merge remote-tracking branch 'origin/dev' into asn-as-targets
liquidsec Feb 18, 2026
d01079d
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Feb 18, 2026
509da46
fix tests
liquidsec Feb 18, 2026
8a1823c
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Feb 18, 2026
a75d639
Merge branch 'dev' into asn-as-targets
liquidsec Feb 19, 2026
741ff20
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Feb 19, 2026
4dcc8ba
Merge branch 'dev' into asn-as-targets
liquidsec Feb 25, 2026
536831c
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Feb 25, 2026
c66d86c
Merge asn-as-targets into virtualhost-upgrade
liquidsec Feb 28, 2026
879eb51
Merge latest asn-as-targets with community.general fix
liquidsec Feb 28, 2026
55850c5
Remove stale test_event_confidence (numeric confidence was removed in…
liquidsec Feb 28, 2026
820b94c
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Mar 2, 2026
f6a8d43
Merge branch 'asn-as-targets' into virtualhost-upgrade
liquidsec Mar 3, 2026
fd39c2f
Merge asn-as-targets, fix waf_bypass for radixtarget 4.x and asndb
liquidsec Mar 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions bbot/core/event/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1604,16 +1604,17 @@ def _pretty_string(self):
return self.data["technology"]


class VHOST(DictHostEvent):
class VIRTUAL_HOST(DictHostEvent):
class _data_validator(BaseModel):
host: str
vhost: str
virtual_host: str
description: str
url: Optional[str] = None
_validate_url = field_validator("url")(validators.validate_url)
_validate_host = field_validator("host")(validators.validate_host)

def _pretty_string(self):
return self.data["vhost"]
return self.data["virtual_host"]


class PROTOCOL(DictHostEvent):
Expand Down
63 changes: 45 additions & 18 deletions bbot/core/helpers/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
import regex as re
import subprocess as sp


from pathlib import Path
from contextlib import suppress
from unidecode import unidecode # noqa F401
from typing import Iterable, Awaitable, Optional
from asyncio import create_task, gather, sleep, wait_for # noqa
from urllib.parse import urlparse, quote, unquote, urlunparse, urljoin # noqa F401

Expand Down Expand Up @@ -2589,30 +2591,55 @@ def parse_port_string(port_string):
return ports


async def as_completed(coros):
async def as_completed(
coroutines: Iterable[Awaitable],
max_concurrent: Optional[int] = None,
):
"""
Yield completed coroutines as they finish with optional concurrency limiting.
All coroutines are scheduled as tasks internally for execution.
"""
Async generator that yields completed Tasks as they are completed.
it = iter(coroutines)

Args:
coros (iterable): An iterable of coroutine objects or asyncio Tasks.
# Prime the running set up to the concurrency limit (or all, if unlimited)
running = set()
limit = max_concurrent or float("inf")
try:
while len(running) < limit:
coro = next(it)
running.add(asyncio.create_task(coro))
except StopIteration:
pass

Yields:
asyncio.Task: A Task object that has completed its execution.
# Drain: yield completed tasks, backfill from the iterator as slots free up
while running:
done, running = await asyncio.wait(running, return_when=asyncio.FIRST_COMPLETED)
for task in done:
# Immediately backfill one slot per completed task, if more work remains
try:
coro = next(it)
running.add(asyncio.create_task(coro))
except StopIteration:
pass
yield task

Examples:
>>> async def main():
... async for task in as_completed([coro1(), coro2(), coro3()]):
... result = task.result()
... print(f'Task completed with result: {result}')

>>> asyncio.run(main())
def get_waf_strings():
"""
tasks = {coro if isinstance(coro, asyncio.Task) else asyncio.create_task(coro): coro for coro in coros}
while tasks:
done, _ = await asyncio.wait(tasks.keys(), return_when=asyncio.FIRST_COMPLETED)
for task in done:
tasks.pop(task)
yield task
Returns a list of common WAF (Web Application Firewall) detection strings.

Returns:
list: List of WAF detection strings

Examples:
>>> waf_strings = get_waf_strings()
>>> "The requested URL was rejected" in waf_strings
True
"""
return [
"The requested URL was rejected",
"This content has been blocked",
]


def clean_dns_record(record):
Expand Down
80 changes: 77 additions & 3 deletions bbot/core/helpers/web/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import warnings
from pathlib import Path
from bs4 import BeautifulSoup
import ipaddress

from bbot.core.engine import EngineClient
from bbot.core.helpers.misc import truncate_filename
Expand Down Expand Up @@ -321,10 +322,11 @@ async def curl(self, *args, **kwargs):
path_override (str, optional): Overrides the request-target to use in the HTTP request line.
head_mode (bool, optional): If True, includes '-I' to fetch headers only. Defaults to None.
raw_body (str, optional): Raw string to be sent in the body of the request.
resolve (dict, optional): Host resolution override as dict with 'host', 'port', 'ip' keys for curl --resolve.
**kwargs: Arbitrary keyword arguments that will be forwarded to the HTTP request function.

Returns:
str: The output of the cURL command.
dict: JSON object with response data and metadata.

Raises:
CurlError: If 'url' is not supplied.
Expand All @@ -338,7 +340,11 @@ async def curl(self, *args, **kwargs):
if not url:
raise CurlError("No URL supplied to CURL helper")

curl_command = ["curl", url, "-s"]
# Use BBOT-specific curl binary
bbot_curl = self.parent_helper.tools_dir / "curl"
if not bbot_curl.exists():
raise CurlError(f"BBOT curl binary not found at {bbot_curl}. Run dependency installation.")
curl_command = [str(bbot_curl), url, "-s"]

raw_path = kwargs.get("raw_path", False)
if raw_path:
Expand Down Expand Up @@ -382,6 +388,12 @@ async def curl(self, *args, **kwargs):
curl_command.append("-m")
curl_command.append(str(timeout))

# mirror the web helper behavior
retries = self.parent_helper.web_config.get("http_retries", 1)
if retries > 0:
curl_command.extend(["--retry", str(retries)])
curl_command.append("--retry-all-errors")

for k, v in headers.items():
if isinstance(v, list):
for x in v:
Expand Down Expand Up @@ -426,9 +438,71 @@ async def curl(self, *args, **kwargs):
if raw_body:
curl_command.append("-d")
curl_command.append(raw_body)

# --resolve <host>:<port>:<ip>
resolve_dict = kwargs.get("resolve", None)

if resolve_dict is not None:
# Validate "resolve" is a dict
if not isinstance(resolve_dict, dict):
raise CurlError("'resolve' must be a dictionary containing 'host', 'port', and 'ip' keys")

# Extract and validate IP (required)
ip = resolve_dict.get("ip")
if not ip:
raise CurlError("'resolve' dictionary requires an 'ip' value")
try:
ipaddress.ip_address(ip)
except ValueError:
raise CurlError(f"Invalid IP address supplied to 'resolve': {ip}")

# Host, port, and ip must ALL be supplied explicitly
host = resolve_dict.get("host")
if not host:
raise CurlError("'resolve' dictionary requires a 'host' value")

if "port" not in resolve_dict:
raise CurlError("'resolve' dictionary requires a 'port' value")
port = resolve_dict["port"]

try:
port = int(port)
except (TypeError, ValueError):
raise CurlError("'port' supplied to resolve must be an integer")
if port < 1 or port > 65535:
raise CurlError("'port' supplied to resolve must be between 1 and 65535")

# Append the --resolve directive
curl_command.append("--resolve")
curl_command.append(f"{host}:{port}:{ip}")

# Always add JSON --write-out format with separator
curl_command.extend(["-w", "\\n---CURL_METADATA---\\n%{json}"])

log.verbose(f"Running curl command: {curl_command}")
output = (await self.parent_helper.run(curl_command)).stdout
return output

# Parse the output to separate content and metadata
import json

parts = output.split("\n---CURL_METADATA---\n")

# Raise CurlError if separator not found - this indicates a problem with our curl implementation
if len(parts) < 2:
raise CurlError(f"Curl output missing expected separator. Got: {output[:200]}...")

response_data = parts[0]
# Take the last part as JSON metadata (in case separator appears in content)
json_data = parts[-1].strip()

# Raise CurlError if JSON parsing fails - this indicates a problem with curl's %{json} output
try:
metadata = json.loads(json_data)
except json.JSONDecodeError as e:
raise CurlError(f"Failed to parse curl JSON metadata: {e}. JSON data: {json_data[:200]}...")

# Combine into final JSON structure
return {"response_data": response_data, **metadata}

def beautifulsoup(
self,
Expand Down
25 changes: 25 additions & 0 deletions bbot/core/shared_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,31 @@
},
]

DEP_CURL = [
{
"name": "Download static curl binary (v8.11.0)",
"get_url": {
"url": "https://github.com/moparisthebest/static-curl/releases/download/v8.11.0/curl-amd64",
"dest": "#{BBOT_TOOLS}/curl",
"mode": "0755",
"force": True,
},
},
{
"name": "Ensure curl binary is executable",
"file": {
"path": "#{BBOT_TOOLS}/curl",
"mode": "0755",
},
},
{
"name": "Verify curl binary works",
"command": "#{BBOT_TOOLS}/curl --version",
"register": "curl_version_output",
"changed_when": False,
},
]

DEP_MASSCAN = [
{
"name": "install os deps (Debian)",
Expand Down
28 changes: 18 additions & 10 deletions bbot/modules/baddns.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from baddns.lib.loader import load_signatures
from .base import BaseModule

import asyncio
import logging


Expand Down Expand Up @@ -54,8 +53,17 @@ async def setup(self):
self.debug(f"Enabled BadDNS Submodules: [{','.join(self.enabled_submodules)}]")
return True

async def _run_module(self, module_instance):
"""Wrapper coroutine that runs a module and returns both the module and result"""
try:
result = await module_instance.dispatch()
return module_instance, result
except Exception as e:
self.warning(f"Task for {module_instance} raised an error: {e}")
return module_instance, None

async def handle_event(self, event):
tasks = []
coroutines = []
for ModuleClass in self.select_modules():
kwargs = {
"http_client_class": self.scan.helpers.web.AsyncClient,
Expand All @@ -70,16 +78,16 @@ async def handle_event(self, event):
kwargs["raw_query_retry_wait"] = 0

module_instance = ModuleClass(event.data, **kwargs)
task = asyncio.create_task(module_instance.dispatch())
tasks.append((module_instance, task))
# Create wrapper coroutine that includes the module instance
coroutine = self._run_module(module_instance)
coroutines.append(coroutine)

async for completed_task in self.helpers.as_completed([task for _, task in tasks]):
module_instance = next((m for m, t in tasks if t == completed_task), None)
async for completed_coro in self.helpers.as_completed(coroutines):
try:
task_result = await completed_task
module_instance, task_result = await completed_coro
except Exception as e:
self.warning(f"Task for {module_instance} raised an error: {e}")
task_result = None
self.warning(f"Wrapper coroutine raised an error: {e}")
continue

if task_result:
results = module_instance.analyze()
Expand Down Expand Up @@ -134,4 +142,4 @@ async def handle_event(self, event):
tags=[f"baddns-{module_instance.name.lower()}"],
context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {{event.data}}',
)
await module_instance.cleanup()
await module_instance.cleanup()
6 changes: 2 additions & 4 deletions bbot/modules/bypass403.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@
"X-Host": "127.0.0.1",
}

# This is planned to be replaced in the future: https://github.com/blacklanternsecurity/bbot/issues/1068
waf_strings = ["The requested URL was rejected"]

for qp in query_payloads:
signatures.append(("GET", "{scheme}://{netloc}/{path}%s" % qp, None, True))
Expand Down Expand Up @@ -107,8 +105,8 @@ async def do_checks(self, compare_helper, event, collapse_threshold):

# In some cases WAFs will respond with a 200 code which causes a false positive
if subject_response is not None:
for ws in waf_strings:
if ws in subject_response.text:
for waf_string in self.helpers.get_waf_strings():
if waf_string in subject_response.text:
self.debug("Rejecting result based on presence of WAF string")
return

Expand Down
8 changes: 5 additions & 3 deletions bbot/modules/generic_ssrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class BaseSubmodule:
severity = "INFO"
paths = []

deps_common = ["curl"]

def __init__(self, generic_ssrf):
self.generic_ssrf = generic_ssrf
self.test_paths = self.create_paths()
Expand All @@ -61,7 +63,7 @@ async def test(self, event):
self.generic_ssrf.debug(f"Sending request to URL: {test_url}")
r = await self.generic_ssrf.helpers.curl(url=test_url)
if r:
self.process(event, r, subdomain_tag)
self.process(event, r["response_data"], subdomain_tag)

def process(self, event, r, subdomain_tag):
response_token = self.generic_ssrf.interactsh_domain.split(".")[0][::-1]
Expand Down Expand Up @@ -123,7 +125,7 @@ async def test(self, event):

for tag, pd in post_data_list:
r = await self.generic_ssrf.helpers.curl(url=test_url, method="POST", post_data=pd)
self.process(event, r, tag)
self.process(event, r["response_data"], tag)


class Generic_XXE(BaseSubmodule):
Expand All @@ -146,7 +148,7 @@ async def test(self, event):
url=test_url, method="POST", raw_body=post_body, headers={"Content-type": "application/xml"}
)
if r:
self.process(event, r, subdomain_tag)
self.process(event, r["response_data"], subdomain_tag)


class generic_ssrf(BaseModule):
Expand Down
Loading
Loading